Adding RSS Feeds

RSS feeds are important for personal blogs. Instead of requiring your visitors to regularly check your page for updates, they can subscribe and receive updates in their personalized streams of news from all blogs they follow. Django offers a comprehensive syndication framework, so adding RSS feeds is very simple.

We add a new import and a new class to our blogapp's views.py:

from django.contrib.syndication.views import Feed

class PostFeed(Feed):

    title = "vladizorov.info"
    link = "/blog/"
    description = "My newest blog posts"

    def items(self):
        return Post.objects.filter(published__exact=True).\
                order_by('-added')[:10]

    def item_title(self, item):
        return item.title

    def item_description(self, item):
        return item.summary

    def item_categories(self, item):
        return item.tags.iterator()

    def item_pubdate(self, item):
        return item.added

We don't need to tell it the URLs of the items because we defined `get_absolute_url` in The Slug that flew South. The `filter(published__exact=True)` lets only published posts through, `order_by('-added')` orders them by newest first, and `[:10]` takes the first 10 elements.

All other functions are pretty straightforward - they just access fields from our `Post` model. `items_categories` expects a string iterable, so we give it an `iterator()` over our tags (note: `tags` is defined as `models.ManyToManyField(Tag)`).

Then in our blogapp's urls.py urlpatterns, we instantiate the class we created above:

from django.conf.urls import patterns, url
from blogapp.views import PostDetail, PostList, PostFeed

urlpatterns = patterns('',
    ...,

    url(r'^feed/$', PostFeed(), name='feed'),

    ....,
)

At this point, assuming your development server is running on localhost:8000, you can try it out on http://localhost:8000/blog/feed/. If everything works and Firefox displays a "Subscribe" window, the only thing left is to add RSS Autodiscovery and a menu link. We add them to base.html, the site-wide template:

<link rel="alternate" type="application/rss+xml" title="RSS"
href="{% url 'blog:feed' %}">

The reason `{% url 'blog:feed' %}` works is because in the home page's urls.py, the blogapp's URLs are included with:

url(r'^blog/', include('blogapp.urls', namespace="blog"))

This way we can refer to them by name in the `blog` namespace. Adding the menu link is similar, the `href` attribute is the same.

The final touches were making the RSS feed more useful to full readers like Liferea by adding `content` tags to items - this tag is actually not supported by default in Django, but it's pretty easy to add it by extending the default RSS feed. After a quick search, I found the solution on django snippets. Thanks, philgyford!

blog comments powered by Disqus