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.

Bookmark and Share
blog comments powered by Disqus