Skip to main content

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 as DefaultFeed). 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

FeatureRSS 2.0 (Rss201rev2Feed)Atom 1.0 (Atom1Feed)
Content Typeapplication/rss+xmlapplication/atom+xml
Date FormatRFC 2822 (pubDate)RFC 3339 (updated, published)
EnclosuresStrictly one per itemMultiple allowed
ID Systemguidid (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: Rss201rev2Feed enforces a limit of exactly one enclosure per item. If you provide more than one, it raises a ValueError.
  • Atom Flexibility: Atom1Feed allows 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 cause SimplerXMLGenerator to fail, as these are invalid in XML 1.0.
  • Stylesheet Types: Passing a single Stylesheet object or a string instead of a list to the stylesheets parameter will raise a TypeError.
  • Atom IDs: If no unique_id is provided for an Atom item, the generator creates a TagURI using get_tag_uri(link, pubdate).