Skip to main content

Creating Syndication Feeds

The syndication framework in this codebase provides a high-level API for generating RSS and Atom feeds. At its core is the Feed class, which acts as a specialized Django view that maps model data to feed elements.

The Feed Class​

The Feed class, located in django.contrib.syndication.views, manages the lifecycle of a feed request. When a Feed instance is called as a view, it performs the following steps:

  1. Object Retrieval: Calls get_object() to fetch any context object based on URL parameters.
  2. Generator Initialization: Initializes a feedgenerator (defaulting to RSS 2.0) with feed-level metadata like title and link.
  3. Item Processing: Iterates over the collection returned by items(), mapping each item to a feed entry using methods like item_title() and item_link().
  4. Response Generation: Returns an HttpResponse with the correct content type and, if publication dates are available, a Last-Modified header for conditional GET support.

Basic Implementation​

A standard feed is created by subclassing Feed and defining basic metadata and the items() method.

from django.contrib.syndication.views import Feed
from myapp.models import Entry

class LatestEntriesFeed(Feed):
title = "My Blog Updates"
link = "/blog/"
description = "Latest posts from my blog."

def items(self):
return Entry.objects.order_by("-published")[:5]

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

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

By default, the framework attempts to call get_absolute_url() on each item to determine the item_link. If your model does not implement this, you must provide an item_link() method in your Feed class.

Dynamic Feeds​

Feeds often need to be filtered based on parameters in the URL (e.g., a feed for a specific category). This is handled by overriding get_object().

As seen in tests/syndication_tests/feeds.py, get_object receives the request and any arguments from the URL configuration:

class CategoryFeed(Feed):
def get_object(self, request, category_id):
return Category.objects.get(pk=category_id)

def title(self, obj):
return "Entries in category: %s" % obj.name

def items(self, obj):
return Entry.objects.filter(category=obj).order_by("-published")

The object returned by get_object() is passed as the first argument to nearly every other feed method, allowing for dynamic metadata and item filtering.

Customizing Item Content​

The framework provides two primary ways to generate the content for feed items: method-based mapping and template-based rendering.

Method-Based Mapping​

You can define methods that take the item as an argument. The framework uses _get_dynamic_attr internally to determine if an attribute is a static value or a callable.

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

def item_categories(self, item):
return [tag.name for tag in item.tags.all()]

Template-Based Rendering​

For complex HTML descriptions or titles, you can use Django templates by setting title_template or description_template.

class TemplateFeed(Feed):
title_template = "syndication/title.html"
description_template = "syndication/description.html"

When templates are used, the framework calls get_context_data() to provide variables to the template. By default, this context includes obj (the item), site (the current site), and request.

Feed Types and Formats​

The default format is RSS 2.0. To switch to Atom 1.0 or another format, change the feed_type attribute using a class from django.utils.feedgenerator.

from django.utils import feedgenerator

class AtomEntriesFeed(LatestEntriesFeed):
feed_type = feedgenerator.Atom1Feed
subtitle = LatestEntriesFeed.description

Media Enclosures​

The framework supports media attachments (enclosures) through item_enclosures(). This is particularly useful for podcasting or image feeds.

def item_enclosures(self, item):
return [
feedgenerator.Enclosure(
url=item.image.url,
length=str(item.image.size),
mime_type="image/jpeg"
)
]

Note that while Atom feeds support multiple enclosures per item, the RSS 2.0 specification limits items to a single enclosure.

Integration and Configuration​

The syndication app is configured via SyndicationConfig in django.contrib.syndication.apps. To use the framework, ensure django.contrib.syndication is in your INSTALLED_APPS.

To expose a feed, instantiate it directly in your URLconf:

from django.urls import path
from .feeds import LatestEntriesFeed

urlpatterns = [
path("rss/latest/", LatestEntriesFeed()),
]

If your feed uses get_object, ensure the URL pattern captures the necessary arguments:

path("rss/category/<int:category_id>/", CategoryFeed()),