dynamically create an xml file in django Jun
29
1
0

Sometimes when communicating to external systems like Flash I am required to dynamically create an XML file. You can utilise the template framework to do the heavy lifting.

It's worth noting that if you need to create syndication feeds you should use the syndication framework, and if you want to create a site map you should use the sitemap framework.

With that being said, lets say you have a model that looks something like this (I'll use a blog post concept for the demo):

# models.py

class Post(models.Model):
    user = models.ForeignKey(User, blank=True, null=True)
    publish = models.BooleanField(default=True)
    title = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)
    edited = models.CharField(max_length=255, blank=True)
    tags = models.ManyToManyField('Tag')
    body = models.TextField()
    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.title

    @models.permalink
    def get_absolute_url(self):
        post_date = self.date_created
        return_vars = {
            'year': post_date.year,
            'month': post_date.month,
            'day': post_date.day,
            'slug': self.slug,
        }

        return('blog_post', (), return_vars)

    ....

    @classmethod
    def get_posts(self, limit=None):
        if limit:
            return Post.objects.filter(publish=True).order_by('-date_created')[0:limit]
        else:
            return Post.objects.filter(publish=True).order_by('-date_created')

You can link a reference to an xml file in urls.py:

# urls.py

urlpatterns = patterns('project.quotes.views',
    ....
    url(r'^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[\w-]+)/, 'post', name='blog_post'),
    url(r'^xml/latest.xml, 'xml_latest', name='blog_xml_latest'),
    ....
)

You can load and render the template which is in the xml format, and return it with mimetype="text/xml". Your view can be something like:

# views.py

template_vars = {...}

def xml_latest(request):
    """
    returns an XML of the most latest posts
    """
    template_vars['posts'] = Post.get_posts(30)
    template_vars['site'] = Site.objects.get_current()

    t = loader.get_template('blog/xml/posts.xml')
    c = Context(template_vars)

    return HttpResponse(t.render(c), mimetype="text/xml")

and your template can be something like:

# posts.xml

<?xml version="1.0" encoding="UTF-8"?>
<posts>
  {% for post in posts %}
  <post>
    <date>{{ post.date_created|date:"M j, Y" }}</date>
    {{ if post.edited }}
    <edited>{{ post.edited|date:"M j, Y" }}</edited>
    {{ endif }}
    <title>{{ post.title }}</title>
    <body>{{ post.body|striptags }}</body>
    <tags>
        {% for tag in post.tags %}
        <tag>
            <name>{{ tag.name }}</name>
            <url>http://{{ site.domain }}{{ tag.get_absolute_url }}</url>
        </tag>
        {% endfor %}
    </tags>
    <absolute_url>http://{{ site.domain }}{{ post.get_absolute_url }}</absolute_url>
  </post>
  {% endfor %}
</posts>

And that's that. There's probably a better more dynamic way to generate the XML file, but this works for me when I need something quick and dirty.

Please let me know if you have any suggestions on how to improve this process.

comments

postgresql cheatsheet Jun
25
1
0

I'm transitioning my databases from MySQL to PostgreSQL. Overall it's been an easy transition. One of the main differences that I had to adjust to is that by default postgres uses the unix user accounts to handle authentication into the CLI. This can be changed in the settings, and it also means that you might want to set the password for the postgres unix user.

Also it's good to note that postgres automatically translates non-strings to lowercase. This is an issue if you do things like camel casing your tables and columns, so it's best to avoid doing so if you're into this habit.

I do find the command lines to be more streamlined and the config to be more straight forward, but that's really just a personal preference.

Here's a rundown of the commands I often use. I'm posting them here for my convenience, but perhaps someone else might also find these useful.

# login
psql -U <user>
psql -U <user> -d <database>
psql -U <user> -h <host> -d <database>


# user management
CREATE USER <user> WITH PASSWORD '<password>'
ALTER USER <user> WITH PASSWORD '<password>'
DROP USER <user>

createuser -D -A -P <user>
psql -U <admin> -c "CREATE USER <user> WITH PASSWORD '<password>'" -d template1


# database
CREATE DATABASE <database>
CREATE DATABASE <database> OWNER <user>
DROP DATABASE <database>

GRANT ALL PRIVILEGES ON DATABASE <database> TO <user>
ALTER TABLE <table> OWNER TO <user>

createdb -O <user> <database>


# install
apt-get install posgresql
apt-get install python-psycopg2

or

apt-get install libpq-dev
pip install psycopg2


# configuration
# pg_hba.conf
host all all 0.0.0.0/0 md5 # open up all connections, used for dev

# postgresql.conf
listen_addresses = '*' # listen for addresses


# dump and load data
pg_dump <database> > <file.sql>
psql <database> < <file.sql>

# from http://developer.postgresql.org/pgdocs/postgres/app-pgdump.html
To dump a database called mydb into a SQL-script file:

$ pg_dump mydb > db.sql

To reload such a script into a (freshly created) database named newdb:

$ psql -d newdb -f db.sql

To dump a database into a custom-format archive file:

$ pg_dump -Fc mydb > db.dump

To reload an archive file into a (freshly created) database named newdb:

$ pg_restore -d newdb db.dump

To dump a single table named mytab:

$ pg_dump -t mytab mydb > db.sql

To dump all tables whose names start with emp in the detroit schema,
except for the table named employee_log:

$ pg_dump -t 'detroit.emp*' -T detroit.employee_log mydb > db.sql

To dump all schemas whose names start with east or west and end in gsm,
excluding any schemas whose names contain the word test:

$ pg_dump -n 'east*gsm' -n 'west*gsm' -N '*test*' mydb > db.sql

The same, using regular expression notation to consolidate the switches:

$ pg_dump -n '(east|west)*gsm' -N '*test*' mydb > db.sql

To dump all database objects except for tables whose names begin with ts_:

$ pg_dump -T 'ts_*' mydb > db.sql

To specify an upper-case or mixed-case name in -t and related switches,
you need to double-quote the name; else it will be folded to lower case (see Patterns).
But double quotes are special to the shell, so in turn they must be quoted.
Thus, to dump a single table with a mixed-case name, you need something like

$ pg_dump -t '"MixedCaseName"' mydb > mytab.sql


# export csv
psql -U <user> <database>
\f ','
\a
\t
\o file.csv
SELECT <statement>
\o
\q

comments

random numbers in javascript Jun
21
1
0

This is a stepwise procedure to generate a random number within a given range in JavaScript.

var number = Math.random(); // generate a random decimal between 0 and 1
number *= 10; // scale the number so that it falls between the range 0 and 10 (or any number you'd like to make the max limit)
number = Math.ceil(number); // round the result up to the nearest whole number

You can combine this into one line to easily create a random number generator:

var number = Math.ceil(10 * Math.random());

comments

fixing jquery ajax caching Jun
16
1
0

Depending on browser settings you might run into problems with caching when calling pages through AJAX. I've run into issues with WebKit based browsers (Chrome, Safari) as it seems they are more aggressive with their caching than Firefox and even IE. This was one of the few times where something worked in IE and not Safari.

If your ajax is calling a dynamically generated page where its content changes over time you need to disable caching on the AJAX call.

In JQuery you can just set the cache parameter to false:

$.ajax({
  url: "/path/to/page/",
  type: "POST",
  cache: false,
  success: function(data){
    ...
  }
});

Another technique that you can do is to generate a random variable on each call to the end of URL to trick the browser.

$.ajax({
  url: "/path/to/page/?v=" Math.ceil(10000*Math.random()),
  type: "POST",
  success: function(data){
    ...
  }
});

comments

create/export and load/import csv files with mysqldump in mysql May
27
1
0

I'm often asked to create csv files to import into other applications. If you're using MySQL it's handy to be able to create a CSV on the fly with mysqldump. This is easily achieved with the following command:

mysqldump -u <user> -p --tab=<directory> --fields-enclosed-by='"' --fields-terminated-by=',' <database> <table>

This creates a .sql dump file and a .txt csv in the directory that you specified with [--tab]. The second part of this operation (the .txt csv creation) will be performed by the MySQL user, so it'll need to have write permissions in the [--tab] directory. Also, the mysql user needs to have the appropriate permissions (I believe it's the FILE privileges).

Alternatively you can import a csv into the database with the following command while logged into the mysql shell using the appropriate database:

LOAD DATA LOCAL INFILE '/path/to/my.csv' INTO TABLE <table>
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(<field1>, <field2>, <field3>);

comments

auto-populate subject and body line in mailto link May
21
1
0

Sometimes I need to auto-populate the subject and body lines inside a mailto link. All you need to do is attach the <subject> and <body> as GET variables.

<a href="mailto:test@example.com?subject=Your subject goes here.&body=Place the body text here.">Send me an email</a>

You can omit the email address if you want the user to be able to choose who she wants to send this to.

<a href="mailto:?subject=Your subject goes here.&body=Place the body text here.">Send me an email</a>

comments

testing 404 500 error pages in django development envirnoment with django-cms May
18
1
0

It's nice to be able to test your 404.html and 500.html templates in your development environment before you push to production.

You could use direct_to_template, but it would be better to use the default Django views that the errors actually use. These are "django.views.defaults.server_error" and "django.views.defaults.page_not_found". All you need to do is to add these to your urlpatterns in a conditonal statement for local development. *** note the += ***

# urls.py

urlpatterns = patterns('',
    ...
)

if settings.LOCAL_DEV:
    urlpatterns += patterns('',
        (r'^404/$', 'django.views.defaults.page_not_found'),
        (r'^500/$', 'django.views.defaults.server_error'),
        (r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT} ),
    )

If you're using Django-CMS this is not going to work because the cms page middleware will call the 404 error before it gets to the LOCAL_DEV urls. This is easily fixed by moving the cms url include to after the LOCAL_DEV urls.

urlpatterns += patterns('',
    url(r'^', include('cms.urls')), # put this near the end
)

comments

css3 border radius May
18
1
0

I keep having to look up the definitions for CSS border radius when it comes to supporting the Mozilla and Webkit specific styles. I'm pasting this here for easy reference.

-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;

-webkit-border-top-left-radius: 6px;
-webkit-border-top-right-radius: 6px;
-webkit-border-bottom-right-radius: 6px;
-webkit-border-bottom-left-radius: 6px;

-moz-border-radius-topleft: 6px;
-moz-border-radius-topright: 6px;
-moz-border-radius-bottomright: 6px;
-moz-border-radius-bottomleft: 6px;

border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 4px;

comments

limit character entry with jquery May
18
1
0

It's common to need to limit character count on user input fields. There's a lot of plugins that you can get this to do it for you. However, when possible I like to reduce the amount of third party scripts. The basic concept is pretty simple to follow in JQuery.

Lets say you have HTML like the following:

<div id="limit"></div>

...
<textarea name="comment" cols="40" rows="10" id="comment"></textarea>
...

You can then bind a keypress event that checks the lengh of the value on the input or textarea.

$('#comment').keypress(function() {
    var MAX_CHAR = 140 - 1;

    $('#limit').text('Characters remaining: ' + ((MAX_CHAR + 1) - $(this).attr('value').length));

    // limit entry
    if($(this).attr('value').length > MAX_CHAR) {
        this.value = this.value.substring(0, MAX_CHAR);
    }
});

This script prints out how many characters are left in the <div id="limit"> and limits the user to inputing 140 characters. No plugins necessary.

Limiting input on the front end is only a convenience for the user. If this functionality is important for your application make sure to make the proper checks and sensitization on the backend when processing the form.

comments

call slugify template tag in django model or view May
17
1
0

Edited: 6.1.2011 - fixed typo

Sometimes I need to slugify something within a django model or view file. Django already has this functionality written as a template filter, and you can reuse this outside of the templates. You can import slugify into your python code like so:

from django.template.defaultfilters import slugify

slugify(<value>)

Which then allows you to write something like:

class Custom(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(blank=True) def save(self): self.slug = slugify(self.name) super(Custom, self).save()

However, if you need this type of functionality depending on your situation it might be easier to set this up using the django admin prepopulated_fields option.

# models.py
class Custom(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField()


# admin.py
class CustomAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}

admin.site.register(Custom, CustomAdmin)

This will auto-populate the slug field while you type the name within the django admin.

comments