Syndication Feeds
The syndication feed system in this codebase provides a low-level framework for generating RSS and Atom feeds. It is built around the SyndicationFeed base class and several format-specific subclasses in django.utils.feedgenerator.
Core Feed Generators
The framework supports three primary feed formats, each implemented as a subclass of SyndicationFeed:
Rss201rev2Feed: The default generator (aliased asDefaultFeed). It produces RSS 2.0 feeds.Atom1Feed: Produces Atom 1.0 feeds (RFC 4287). This format is generally more flexible, supporting multiple media enclosures per item.RssUserland091Feed: A legacy generator for RSS 0.91, providing a simplified set of elements (title, link, and description only).
Comparison of Formats
| Feature | RSS 2.0 (Rss201rev2Feed) | Atom 1.0 (Atom1Feed) |
|---|---|---|
| Content Type | application/rss+xml | application/atom+xml |
| Date Format | RFC 2822 (pubDate) | RFC 3339 (updated, published) |
| Enclosures | Strictly one per item | Multiple allowed |
| ID System | guid | id (TagURI by default) |
Basic Usage
Generating a feed involves instantiating a generator, adding items, and writing the result to a file-like object or a string.
from django.utils import feedgenerator
# 1. Initialize the feed with metadata
feed = feedgenerator.Rss201rev2Feed(
title="My Site Feed",
link="https://example.com/",
description="Latest updates from my site.",
language="en",
)
# 2. Add items to the feed
feed.add_item(
title="New Feature Released",
link="https://example.com/news/1/",
description="We just launched a new feature!",
pubdate=datetime.datetime.now()
)
# 3. Output the feed
# To a string:
feed_content = feed.writeString('utf-8')
# Or to a file-like object:
with open('feed.xml', 'w') as fp:
feed.write(fp, 'utf-8')
Customizing Feed Output
For specialized XML requirements, you can subclass the existing generators and override specific hook methods. The generators use SimplerXMLGenerator (passed as handler) to build the XML tree.
Customizing Root and Item Elements
The primary hooks for adding custom XML tags are add_root_elements and add_item_elements.
class CustomAtomFeed(feedgenerator.Atom1Feed):
def root_attributes(self):
attrs = super().root_attributes()
attrs["custom-namespace"] = "http://example.com/ns"
return attrs
def add_root_elements(self, handler):
super().add_root_elements(handler)
handler.addQuickElement("extra_info", "Some global data")
def add_item_elements(self, handler, item):
super().add_item_elements(handler, item)
# Access custom data passed via add_item(**kwargs)
if "internal_id" in item:
handler.addQuickElement("internal", item["internal_id"])
Real-World Example: GeoRSS
The django.contrib.gis.feeds.GeoRSSFeed demonstrates how to extend Rss201rev2Feed to include geographic information by adding a namespace and custom elements:
class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin):
def rss_attributes(self):
attrs = super().rss_attributes()
attrs["xmlns:georss"] = "http://www.georss.org/georss"
return attrs
def add_item_elements(self, handler, item):
super().add_item_elements(handler, item)
# Custom logic to add <georss:point> etc.
self.add_georss_element(handler, item)
Media Enclosures and Stylesheets
Enclosures
The Enclosure class represents media attachments (like podcasts or images).
- RSS 2.0 Limitation:
Rss201rev2Feedenforces a limit of exactly one enclosure per item. If you provide more than one, it raises aValueError. - Atom Flexibility:
Atom1Feedallows any number of enclosures.
from django.utils.feedgenerator import Enclosure
feed.add_item(
title="Podcast Episode 1",
link="https://example.com/podcast/1",
description="Our first episode.",
enclosures=[
Enclosure(url="https://example.com/audio/ep1.mp3", length="12345", mime_type="audio/mpeg")
]
)
Stylesheets
You can attach XML stylesheets (XSLT or CSS) to a feed using the Stylesheet class. The stylesheets argument in SyndicationFeed must be a list.
from django.utils.feedgenerator import Stylesheet
feed = feedgenerator.Rss201rev2Feed(
title="Styled Feed",
link="https://example.com/",
description="A feed with a stylesheet",
stylesheets=[Stylesheet("https://example.com/rss.xsl")]
)
Technical Implementation Details
Date Handling
The framework provides two utility functions for date formatting:
rfc2822_date(date): Used by RSS feeds (e.g.,Sat, 07 Sep 2024 00:00:00 +0000).rfc3339_date(date): Used by Atom feeds (e.g.,2024-09-07T00:00:00Z).
The latest_post_date() method on SyndicationFeed automatically determines the most recent pubdate or updateddate across all items to populate the feed's top-level timestamp.
URL Conversion
All URLs passed to the feed (links, author links, enclosure URLs) are processed through iri_to_uri to ensure they are valid URIs.
Constraints and Gotchas
- Control Characters: Content containing control characters (e.g.,
\x00) will causeSimplerXMLGeneratorto fail, as these are invalid in XML 1.0. - Stylesheet Types: Passing a single
Stylesheetobject or a string instead of a list to thestylesheetsparameter will raise aTypeError. - Atom IDs: If no
unique_idis provided for an Atom item, the generator creates a TagURI usingget_tag_uri(link, pubdate).