---
title: "The syndication feed framework"
version: 5.1
locale: pt-br
source: https://docs.djangoproject.com/pt-br/5.1/ref/contrib/syndication/
canonical: https://djangodocs.dev/pt-br/5.1/ref/contrib/syndication/
---
# The syndication feed framework

Django comes with a high-level syndication-feed-generating framework for
creating [RSS](https://developer.mozilla.org/en-US/docs/Glossary/RSS) and [**Atom**](https://datatracker.ietf.org/doc/html/rfc4287.html) feeds.

To create any syndication feed, all you have to do is write a short
Python class. You can create as many feeds as you want.

Django also comes with a lower-level feed-generating API. Use this if
you want to generate feeds outside of a web context, or in some other
lower-level way.

## The high-level framework

### Visão Geral

The high-level feed-generating framework is supplied by the
[`Feed`](#django.contrib.syndication.views.Feed) class. To create a
feed, write a [`Feed`](#django.contrib.syndication.views.Feed) class
and point to an instance of it in your [URLconf](/pt-br/5.1/topics/http/urls/).

### `Feed` classes

A [`Feed`](#django.contrib.syndication.views.Feed) class is a Python
class that represents a syndication feed. A feed can be simple (e.g.,
a “site news” feed, or a basic feed displaying the latest entries of a
blog) or more complex (e.g., a feed displaying all the blog entries in
a particular category, where the category is variable).

Feed classes subclass [`django.contrib.syndication.views.Feed`](#django.contrib.syndication.views.Feed).
They can live anywhere in your codebase.

Instances of [`Feed`](#django.contrib.syndication.views.Feed) classes
are views which can be used in your [URLconf](/pt-br/5.1/topics/http/urls/).

### A simple example

This simple example, taken from a hypothetical police beat news site describes
a feed of the latest five news items:

```
from django.contrib.syndication.views import Feed
from django.urls import reverse
from policebeat.models import NewsItem

class LatestEntriesFeed(Feed):
    title = "Police beat site news"
    link = "/sitenews/"
    description = "Updates on changes and additions to police beat central."

    def items(self):
        return NewsItem.objects.order_by("-pub_date")[:5]

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

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

    # item_link is only needed if NewsItem has no get_absolute_url method.
    def item_link(self, item):
        return reverse("news-item", args=[item.pk])
```

To connect a URL to this feed, put an instance of the Feed object in
your [URLconf](/pt-br/5.1/topics/http/urls/). For example:

```
from django.urls import path
from myproject.feeds import LatestEntriesFeed

urlpatterns = [
    # ...
    path("latest/feed/", LatestEntriesFeed()),
    # ...
]
```

Note:

- The Feed class subclasses [`django.contrib.syndication.views.Feed`](#django.contrib.syndication.views.Feed).
- `title`, `link` and `description` correspond to the
  standard RSS `<title>`, `<link>` and `<description>` elements,
  respectively.
- `items()` is, a method that returns a list of objects that should be
  included in the feed as `<item>` elements. Although this example returns
  `NewsItem` objects using Django’s [object-relational mapper](/pt-br/5.1/ref/models/querysets/), `items()` doesn’t have to return model instances.
  Although you get a few bits of functionality “for free” by using Django
  models, `items()` can return any type of object you want.
- If you’re creating an Atom feed, rather than an RSS feed, set the
  `subtitle` attribute instead of the `description` attribute.
  See [Publishing Atom and RSS feeds in tandem](#publishing-atom-and-rss-feeds-in-tandem), later, for an example.

One thing is left to do. In an RSS feed, each `<item>` has a `<title>`,
`<link>` and `<description>`. We need to tell the framework what data to put
into those elements.

- For the contents of `<title>` and `<description>`, Django tries
  calling the methods `item_title()` and `item_description()` on
  the [`Feed`](#django.contrib.syndication.views.Feed) class. They are passed
  a single parameter, `item`, which is the object itself. These are
  optional; by default, the string representation of the object is used for
  both.

  If you want to do any special formatting for either the title or
  description, [Django templates](/pt-br/5.1/ref/templates/language/) can be used
  instead. Their paths can be specified with the `title_template` and
  `description_template` attributes on the
  [`Feed`](#django.contrib.syndication.views.Feed) class. The templates are
  rendered for each item and are passed two template context variables:

  - `{{ obj }}` – The current object (one of whichever objects you
    returned in `items()`).
  - `{{ site }}` – A [`django.contrib.sites.models.Site`](/pt-br/5.1/ref/contrib/sites/#django.contrib.sites.models.Site) object
    representing the current site. This is useful for `{{ site.domain
    }}` or `{{ site.name }}`. If you do *not* have the Django sites
    framework installed, this will be set to a
    [`RequestSite`](/pt-br/5.1/ref/contrib/sites/#django.contrib.sites.requests.RequestSite) object. See the
    [RequestSite section of the sites framework documentation](/pt-br/5.1/ref/contrib/sites/#id3) for more.

  See [a complex example](#a-complex-example) below that uses a description template.

  #### `Feed.get_context_data(**kwargs)`

  There is also a way to pass additional information to title and description
  templates, if you need to supply more than the two variables mentioned
  before. You can provide your implementation of `get_context_data` method
  in your `Feed` subclass. For example:

  ```
  from mysite.models import Article
  from django.contrib.syndication.views import Feed

  class ArticlesFeed(Feed):
      title = "My articles"
      description_template = "feeds/articles.html"

      def items(self):
          return Article.objects.order_by("-pub_date")[:5]

      def get_context_data(self, **kwargs):
          context = super().get_context_data(**kwargs)
          context["foo"] = "bar"
          return context
  ```

  E o template:

  ```html+django
  Something about {{ foo }}: {{ obj.description }}
  ```

  This method will be called once per each item in the list returned by
  `items()` with the following keyword arguments:

  - `item`: the current item. For backward compatibility reasons, the name
    of this context variable is `{{ obj }}`.
  - `obj`: the object returned by `get_object()`. By default this is not
    exposed to the templates to avoid confusion with `{{ obj }}` (see above),
    but you can use it in your implementation of `get_context_data()`.
  - `site`: current site as described above.
  - `request`: current request.

  The behavior of `get_context_data()` mimics that of
  [generic views](/pt-br/5.1/topics/class-based-views/generic-display/#adding-extra-context) \- you’re supposed to call
  `super()` to retrieve context data from parent class, add your data
  and return the modified dictionary.
- To specify the contents of `<link>`, you have two options. For each item
  in `items()`, Django first tries calling the
  `item_link()` method on the
  [`Feed`](#django.contrib.syndication.views.Feed) class. In a similar way to
  the title and description, it is passed it a single parameter,
  `item`. If that method doesn’t exist, Django tries executing a
  `get_absolute_url()` method on that object. Both
  `get_absolute_url()` and `item_link()` should return the
  item’s URL as a normal Python string. As with `get_absolute_url()`, the
  result of `item_link()` will be included directly in the URL, so you
  are responsible for doing all necessary URL quoting and conversion to
  ASCII inside the method itself.

### Um exemplo complexo

The framework also supports more complex feeds, via arguments.

For example, a website could offer an RSS feed of recent crimes for every
police beat in a city. It’d be silly to create a separate
[`Feed`](#django.contrib.syndication.views.Feed) class for each police beat; that
would violate the [DRY principle](/pt-br/5.1/misc/design-philosophies/#dry) and would couple data to
programming logic. Instead, the syndication framework lets you access the
arguments passed from your [URLconf](/pt-br/5.1/topics/http/urls/) so feeds can output
items based on information in the feed’s URL.

The police beat feeds could be accessible via URLs like this:

- `/beats/613/rss/` – Returns recent crimes for beat 613.
- `/beats/1424/rss/` – Returns recent crimes for beat 1424.

These can be matched with a [URLconf](/pt-br/5.1/topics/http/urls/) line such as:

```
path("beats/<int:beat_id>/rss/", BeatFeed()),
```

Like a view, the arguments in the URL are passed to the `get_object()`
method along with the request object.

Here’s the code for these beat-specific feeds:

```
from django.contrib.syndication.views import Feed

class BeatFeed(Feed):
    description_template = "feeds/beat_description.html"

    def get_object(self, request, beat_id):
        return Beat.objects.get(pk=beat_id)

    def title(self, obj):
        return "Police beat central: Crimes for beat %s" % obj.beat

    def link(self, obj):
        return obj.get_absolute_url()

    def description(self, obj):
        return "Crimes recently reported in police beat %s" % obj.beat

    def items(self, obj):
        return Crime.objects.filter(beat=obj).order_by("-crime_date")[:30]
```

To generate the feed’s `<title>`, `<link>` and `<description>`, Django
uses the `title()`, `link()` and `description()` methods. In
the previous example, they were string class attributes, but this example
illustrates that they can be either strings *or* methods. For each of
`title`, `link` and `description`, Django follows this
algorithm:

- First, it tries to call a method, passing the `obj` argument, where
  `obj` is the object returned by `get_object()`.
- Failing that, it tries to call a method with no arguments.
- Failing that, it uses the class attribute.

Also note that `items()` also follows the same algorithm – first, it
tries `items(obj)`, then `items()`, then finally an `items`
class attribute (which should be a list).

We are using a template for the item descriptions. It can be as minimal as
this:

```html+django
{{ obj.description }}
```

However, you are free to add formatting as desired.

The `ExampleFeed` class below gives full documentation on methods and
attributes of [`Feed`](#django.contrib.syndication.views.Feed) classes.

### Specifying the type of feed

By default, feeds produced in this framework use RSS 2.0.

To change that, add a `feed_type` attribute to your
[`Feed`](#django.contrib.syndication.views.Feed) class, like so:

```
from django.utils.feedgenerator import Atom1Feed

class MyFeed(Feed):
    feed_type = Atom1Feed
```

Note that you set `feed_type` to a class object, not an instance.

Currently available feed types are:

- [`django.utils.feedgenerator.Rss201rev2Feed`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.Rss201rev2Feed) (RSS 2.01. Default.)
- [`django.utils.feedgenerator.RssUserland091Feed`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.RssUserland091Feed) (RSS 0.91.)
- [`django.utils.feedgenerator.Atom1Feed`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.Atom1Feed) (Atom 1.0.)

### Enclosures

To specify enclosures, such as those used in creating podcast feeds, use the
`item_enclosures` hook or, alternatively and if you only have a single
enclosure per item, the `item_enclosure_url`, `item_enclosure_length`, and
`item_enclosure_mime_type` hooks. See the `ExampleFeed` class below for
usage examples.

### Language

Feeds created by the syndication framework automatically include the
appropriate `<language>` tag (RSS 2.0) or `xml:lang` attribute (Atom). By
default, this is [`django.utils.translation.get_language()`](/pt-br/5.1/ref/utils/#django.utils.translation.get_language). You can change it
by setting the `language` class attribute.

### URLs

The `link` method/attribute can return either an absolute path (e.g.
`"/blog/"`) or a URL with the fully-qualified domain and protocol (e.g.
`"https://www.example.com/blog/"`). If `link` doesn’t return the domain,
the syndication framework will insert the domain of the current site, according
to your [`SITE_ID setting`](/pt-br/5.1/ref/settings/#std-setting-SITE_ID).

Atom feeds require a `<link rel="self">` that defines the feed’s current
location. The syndication framework populates this automatically, using the
domain of the current site according to the [`SITE_ID`](/pt-br/5.1/ref/settings/#std-setting-SITE_ID) setting.

### Publishing Atom and RSS feeds in tandem

Some developers like to make available both Atom *and* RSS versions of their
feeds. To do that, you can create a subclass of your
[`Feed`](#django.contrib.syndication.views.Feed) class and set the `feed_type`
to something different. Then update your URLconf to add the extra versions.

Here’s a full example:

```
from django.contrib.syndication.views import Feed
from policebeat.models import NewsItem
from django.utils.feedgenerator import Atom1Feed

class RssSiteNewsFeed(Feed):
    title = "Police beat site news"
    link = "/sitenews/"
    description = "Updates on changes and additions to police beat central."

    def items(self):
        return NewsItem.objects.order_by("-pub_date")[:5]

class AtomSiteNewsFeed(RssSiteNewsFeed):
    feed_type = Atom1Feed
    subtitle = RssSiteNewsFeed.description
```

> **Note**
>
> In this example, the RSS feed uses a `description` while the Atom
> feed uses a `subtitle`. That’s because Atom feeds don’t provide for
> a feed-level “description,” but they *do* provide for a “subtitle.”
>
> If you provide a `description` in your
> [`Feed`](#django.contrib.syndication.views.Feed) class, Django will *not*
> automatically put that into the `subtitle` element, because a
> subtitle and description are not necessarily the same thing. Instead, you
> should define a `subtitle` attribute.
>
> In the above example, we set the Atom feed’s `subtitle` to the RSS feed’s
> `description`, because it’s quite short already.

And the accompanying URLconf:

```
from django.urls import path
from myproject.feeds import AtomSiteNewsFeed, RssSiteNewsFeed

urlpatterns = [
    # ...
    path("sitenews/rss/", RssSiteNewsFeed()),
    path("sitenews/atom/", AtomSiteNewsFeed()),
    # ...
]
```

### `Feed` class reference

#### `class views.Feed`

This example illustrates all possible attributes and methods for a
[`Feed`](#django.contrib.syndication.views.Feed) class:

```
from django.contrib.syndication.views import Feed
from django.utils import feedgenerator

class ExampleFeed(Feed):
    # FEED TYPE -- Optional. This should be a class that subclasses
    # django.utils.feedgenerator.SyndicationFeed. This designates
    # which type of feed this should be: RSS 2.0, Atom 1.0, etc. If
    # you don't specify feed_type, your feed will be RSS 2.0. This
    # should be a class, not an instance of the class.

    feed_type = feedgenerator.Rss201rev2Feed

    # TEMPLATE NAMES -- Optional. These should be strings
    # representing names of Django templates that the system should
    # use in rendering the title and description of your feed items.
    # Both are optional. If a template is not specified, the
    # item_title() or item_description() methods are used instead.

    title_template = None
    description_template = None

    # LANGUAGE -- Optional. This should be a string specifying a language
    # code. Defaults to django.utils.translation.get_language().
    language = "de"

    # TITLE -- One of the following three is required. The framework
    # looks for them in this order.

    def title(self, obj):
        """
        Takes the object returned by get_object() and returns the
        feed's title as a normal Python string.
        """

    def title(self):
        """
        Returns the feed's title as a normal Python string.
        """

    title = "foo"  # Hard-coded title.

    # LINK -- One of the following three is required. The framework
    # looks for them in this order.

    def link(self, obj):
        """
        # Takes the object returned by get_object() and returns the URL
        # of the HTML version of the feed as a normal Python string.
        """

    def link(self):
        """
        Returns the URL of the HTML version of the feed as a normal Python
        string.
        """

    link = "/blog/"  # Hard-coded URL.

    # FEED_URL -- One of the following three is optional. The framework
    # looks for them in this order.

    def feed_url(self, obj):
        """
        # Takes the object returned by get_object() and returns the feed's
        # own URL as a normal Python string.
        """

    def feed_url(self):
        """
        Returns the feed's own URL as a normal Python string.
        """

    feed_url = "/blog/rss/"  # Hard-coded URL.

    # GUID -- One of the following three is optional. The framework looks
    # for them in this order. This property is only used for Atom feeds
    # (where it is the feed-level ID element). If not provided, the feed
    # link is used as the ID.

    def feed_guid(self, obj):
        """
        Takes the object returned by get_object() and returns the globally
        unique ID for the feed as a normal Python string.
        """

    def feed_guid(self):
        """
        Returns the feed's globally unique ID as a normal Python string.
        """

    feed_guid = "/foo/bar/1234"  # Hard-coded guid.

    # DESCRIPTION -- One of the following three is required. The framework
    # looks for them in this order.

    def description(self, obj):
        """
        Takes the object returned by get_object() and returns the feed's
        description as a normal Python string.
        """

    def description(self):
        """
        Returns the feed's description as a normal Python string.
        """

    description = "Foo bar baz."  # Hard-coded description.

    # AUTHOR NAME --One of the following three is optional. The framework
    # looks for them in this order.

    def author_name(self, obj):
        """
        Takes the object returned by get_object() and returns the feed's
        author's name as a normal Python string.
        """

    def author_name(self):
        """
        Returns the feed's author's name as a normal Python string.
        """

    author_name = "Sally Smith"  # Hard-coded author name.

    # AUTHOR EMAIL --One of the following three is optional. The framework
    # looks for them in this order.

    def author_email(self, obj):
        """
        Takes the object returned by get_object() and returns the feed's
        author's email as a normal Python string.
        """

    def author_email(self):
        """
        Returns the feed's author's email as a normal Python string.
        """

    author_email = "test@example.com"  # Hard-coded author email.

    # AUTHOR LINK --One of the following three is optional. The framework
    # looks for them in this order. In each case, the URL should include
    # the scheme (such as "https://") and domain name.

    def author_link(self, obj):
        """
        Takes the object returned by get_object() and returns the feed's
        author's URL as a normal Python string.
        """

    def author_link(self):
        """
        Returns the feed's author's URL as a normal Python string.
        """

    author_link = "https://www.example.com/"  # Hard-coded author URL.

    # CATEGORIES -- One of the following three is optional. The framework
    # looks for them in this order. In each case, the method/attribute
    # should return an iterable object that returns strings.

    def categories(self, obj):
        """
        Takes the object returned by get_object() and returns the feed's
        categories as iterable over strings.
        """

    def categories(self):
        """
        Returns the feed's categories as iterable over strings.
        """

    categories = ["python", "django"]  # Hard-coded list of categories.

    # COPYRIGHT NOTICE -- One of the following three is optional. The
    # framework looks for them in this order.

    def feed_copyright(self, obj):
        """
        Takes the object returned by get_object() and returns the feed's
        copyright notice as a normal Python string.
        """

    def feed_copyright(self):
        """
        Returns the feed's copyright notice as a normal Python string.
        """

    feed_copyright = "Copyright (c) 2007, Sally Smith"  # Hard-coded copyright notice.

    # TTL -- One of the following three is optional. The framework looks
    # for them in this order. Ignored for Atom feeds.

    def ttl(self, obj):
        """
        Takes the object returned by get_object() and returns the feed's
        TTL (Time To Live) as a normal Python string.
        """

    def ttl(self):
        """
        Returns the feed's TTL as a normal Python string.
        """

    ttl = 600  # Hard-coded Time To Live.

    # ITEMS -- One of the following three is required. The framework looks
    # for them in this order.

    def items(self, obj):
        """
        Takes the object returned by get_object() and returns a list of
        items to publish in this feed.
        """

    def items(self):
        """
        Returns a list of items to publish in this feed.
        """

    items = ["Item 1", "Item 2"]  # Hard-coded items.

    # GET_OBJECT -- This is required for feeds that publish different data
    # for different URL parameters. (See "A complex example" above.)

    def get_object(self, request, *args, **kwargs):
        """
        Takes the current request and the arguments from the URL, and
        returns an object represented by this feed. Raises
        django.core.exceptions.ObjectDoesNotExist on error.
        """

    # ITEM TITLE AND DESCRIPTION -- If title_template or
    # description_template are not defined, these are used instead. Both are
    # optional, by default they will use the string representation of the
    # item.

    def item_title(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        title as a normal Python string.
        """

    def item_title(self):
        """
        Returns the title for every item in the feed.
        """

    item_title = "Breaking News: Nothing Happening"  # Hard-coded title.

    def item_description(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        description as a normal Python string.
        """

    def item_description(self):
        """
        Returns the description for every item in the feed.
        """

    item_description = "A description of the item."  # Hard-coded description.

    def get_context_data(self, **kwargs):
        """
        Returns a dictionary to use as extra context if either
        description_template or item_template are used.

        Default implementation preserves the old behavior
        of using {'obj': item, 'site': current_site} as the context.
        """

    # ITEM LINK -- One of these three is required. The framework looks for
    # them in this order.

    # First, the framework tries the two methods below, in
    # order. Failing that, it falls back to the get_absolute_url()
    # method on each item returned by items().

    def item_link(self, item):
        """
        Takes an item, as returned by items(), and returns the item's URL.
        """

    def item_link(self):
        """
        Returns the URL for every item in the feed.
        """

    # ITEM_GUID -- The following method is optional. If not provided, the
    # item's link is used by default.

    def item_guid(self, obj):
        """
        Takes an item, as return by items(), and returns the item's ID.
        """

    # ITEM_GUID_IS_PERMALINK -- The following method is optional. If
    # provided, it sets the 'isPermaLink' attribute of an item's
    # GUID element. This method is used only when 'item_guid' is
    # specified.

    def item_guid_is_permalink(self, obj):
        """
        Takes an item, as returned by items(), and returns a boolean.
        """

    item_guid_is_permalink = False  # Hard coded value

    # ITEM AUTHOR NAME -- One of the following three is optional. The
    # framework looks for them in this order.

    def item_author_name(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        author's name as a normal Python string.
        """

    def item_author_name(self):
        """
        Returns the author name for every item in the feed.
        """

    item_author_name = "Sally Smith"  # Hard-coded author name.

    # ITEM AUTHOR EMAIL --One of the following three is optional. The
    # framework looks for them in this order.
    #
    # If you specify this, you must specify item_author_name.

    def item_author_email(self, obj):
        """
        Takes an item, as returned by items(), and returns the item's
        author's email as a normal Python string.
        """

    def item_author_email(self):
        """
        Returns the author email for every item in the feed.
        """

    item_author_email = "test@example.com"  # Hard-coded author email.

    # ITEM AUTHOR LINK -- One of the following three is optional. The
    # framework looks for them in this order. In each case, the URL should
    # include the scheme (such as "https://") and domain name.
    #
    # If you specify this, you must specify item_author_name.

    def item_author_link(self, obj):
        """
        Takes an item, as returned by items(), and returns the item's
        author's URL as a normal Python string.
        """

    def item_author_link(self):
        """
        Returns the author URL for every item in the feed.
        """

    item_author_link = "https://www.example.com/"  # Hard-coded author URL.

    # ITEM ENCLOSURES -- One of the following three is optional. The
    # framework looks for them in this order. If one of them is defined,
    # ``item_enclosure_url``, ``item_enclosure_length``, and
    # ``item_enclosure_mime_type`` will have no effect.

    def item_enclosures(self, item):
        """
        Takes an item, as returned by items(), and returns a list of
        ``django.utils.feedgenerator.Enclosure`` objects.
        """

    def item_enclosures(self):
        """
        Returns the ``django.utils.feedgenerator.Enclosure`` list for every
        item in the feed.
        """

    item_enclosures = []  # Hard-coded enclosure list

    # ITEM ENCLOSURE URL -- One of these three is required if you're
    # publishing enclosures and you're not using ``item_enclosures``. The
    # framework looks for them in this order.

    def item_enclosure_url(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        enclosure URL.
        """

    def item_enclosure_url(self):
        """
        Returns the enclosure URL for every item in the feed.
        """

    item_enclosure_url = "/foo/bar.mp3"  # Hard-coded enclosure link.

    # ITEM ENCLOSURE LENGTH -- One of these three is required if you're
    # publishing enclosures and you're not using ``item_enclosures``. The
    # framework looks for them in this order. In each case, the returned
    # value should be either an integer, or a string representation of the
    # integer, in bytes.

    def item_enclosure_length(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        enclosure length.
        """

    def item_enclosure_length(self):
        """
        Returns the enclosure length for every item in the feed.
        """

    item_enclosure_length = 32000  # Hard-coded enclosure length.

    # ITEM ENCLOSURE MIME TYPE -- One of these three is required if you're
    # publishing enclosures and you're not using ``item_enclosures``. The
    # framework looks for them in this order.

    def item_enclosure_mime_type(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        enclosure MIME type.
        """

    def item_enclosure_mime_type(self):
        """
        Returns the enclosure MIME type for every item in the feed.
        """

    item_enclosure_mime_type = "audio/mpeg"  # Hard-coded enclosure MIME type.

    # ITEM PUBDATE -- It's optional to use one of these three. This is a
    # hook that specifies how to get the pubdate for a given item.
    # In each case, the method/attribute should return a Python
    # datetime.datetime object.

    def item_pubdate(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        pubdate.
        """

    def item_pubdate(self):
        """
        Returns the pubdate for every item in the feed.
        """

    item_pubdate = datetime.datetime(2005, 5, 3)  # Hard-coded pubdate.

    # ITEM UPDATED -- It's optional to use one of these three. This is a
    # hook that specifies how to get the updateddate for a given item.
    # In each case, the method/attribute should return a Python
    # datetime.datetime object.

    def item_updateddate(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        updateddate.
        """

    def item_updateddate(self):
        """
        Returns the updateddate for every item in the feed.
        """

    item_updateddate = datetime.datetime(2005, 5, 3)  # Hard-coded updateddate.

    # ITEM CATEGORIES -- It's optional to use one of these three. This is
    # a hook that specifies how to get the list of categories for a given
    # item. In each case, the method/attribute should return an iterable
    # object that returns strings.

    def item_categories(self, item):
        """
        Takes an item, as returned by items(), and returns the item's
        categories.
        """

    def item_categories(self):
        """
        Returns the categories for every item in the feed.
        """

    item_categories = ["python", "django"]  # Hard-coded categories.

    # ITEM COPYRIGHT NOTICE (only applicable to Atom feeds) -- One of the
    # following three is optional. The framework looks for them in this
    # order.

    def item_copyright(self, obj):
        """
        Takes an item, as returned by items(), and returns the item's
        copyright notice as a normal Python string.
        """

    def item_copyright(self):
        """
        Returns the copyright notice for every item in the feed.
        """

    item_copyright = "Copyright (c) 2007, Sally Smith"  # Hard-coded copyright notice.

    # ITEM COMMENTS URL -- It's optional to use one of these three. This is
    # a hook that specifies how to get the URL of a page for comments for a
    # given item.

    def item_comments(self, obj):
        """
        Takes an item, as returned by items(), and returns the item's
        comments URL as a normal Python string.
        """

    def item_comments(self):
        """
        Returns the comments URL for every item in the feed.
        """

    item_comments = "https://www.example.com/comments"  # Hard-coded comments URL
```

## The low-level framework

Behind the scenes, the high-level RSS framework uses a lower-level framework
for generating feeds’ XML. This framework lives in a single module:
[django/utils/feedgenerator.py](https://github.com/django/django/blob/stable/5.1.x/django/utils/feedgenerator.py).

You use this framework on your own, for lower-level feed generation. You can
also create custom feed generator subclasses for use with the `feed_type`
`Feed` option.

### `SyndicationFeed` classes

The [`feedgenerator`](/pt-br/5.1/ref/utils/#module-django.utils.feedgenerator) module contains a base class:

- [`django.utils.feedgenerator.SyndicationFeed`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.SyndicationFeed)

and several subclasses:

- [`django.utils.feedgenerator.RssUserland091Feed`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.RssUserland091Feed)
- [`django.utils.feedgenerator.Rss201rev2Feed`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.Rss201rev2Feed)
- [`django.utils.feedgenerator.Atom1Feed`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.Atom1Feed)

Each of these three classes knows how to render a certain type of feed as XML.
They share this interface:

**[`SyndicationFeed.__init__()`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.SyndicationFeed.__init__)**

  Initialize the feed with the given dictionary of metadata, which applies to
  the entire feed. Required keyword arguments are:

  - `title`
  - `link`
  - `description`

  There’s also a bunch of other optional keywords:

  - `language`
  - `author_email`
  - `author_name`
  - `author_link`
  - `subtitle`
  - `categories`
  - `feed_url`
  - `feed_copyright`
  - `feed_guid`
  - `ttl`

  Any extra keyword arguments you pass to `__init__` will be stored in
  `self.feed` for use with [custom feed generators](#custom-feed-generators).

  All parameters should be strings, except `categories`, which should be a
  sequence of strings. Beware that some control characters
  are [not allowed](https://www.w3.org/International/questions/qa-controls)
  in XML documents. If your content has some of them, you might encounter a
  [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) when producing the feed.

**[`SyndicationFeed.add_item()`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.SyndicationFeed.add_item)**

  Add an item to the feed with the given parameters.

  Required keyword arguments are:

  - `title`
  - `link`
  - `description`

  Optional keyword arguments are:

  - `author_email`
  - `author_name`
  - `author_link`
  - `pubdate`
  - `comments`
  - `unique_id`
  - `enclosures`
  - `categories`
  - `item_copyright`
  - `ttl`
  - `updateddate`

  Extra keyword arguments will be stored for [custom feed generators](#custom-feed-generators).

  All parameters, if given, should be strings, except:

  - `pubdate` should be a Python  [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) object.
  - `updateddate` should be a Python  [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) object.
  - `enclosures` should be a list of
    [`django.utils.feedgenerator.Enclosure`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.Enclosure) instances.
  - `categories` should be a sequence of strings.

**[`SyndicationFeed.write()`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.SyndicationFeed.write)**

  Outputs the feed in the given encoding to outfile, which is a file-like object.

**[`SyndicationFeed.writeString()`](/pt-br/5.1/ref/utils/#django.utils.feedgenerator.SyndicationFeed.writeString)**

  Returns the feed as a string in the given encoding.

For example, to create an Atom 1.0 feed and print it to standard output:

```pycon
>>> from django.utils import feedgenerator
>>> from datetime import datetime
>>> f = feedgenerator.Atom1Feed(
...     title="My Blog",
...     link="https://www.example.com/",
...     description="In which I write about what I ate today.",
...     language="en",
...     author_name="Myself",
...     feed_url="https://example.com/atom.xml",
... )
>>> f.add_item(
...     title="Hot dog today",
...     link="https://www.example.com/entries/1/",
...     pubdate=datetime.now(),
...     description="<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>",
... )
>>> print(f.writeString("UTF-8"))
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
...
</feed>
```

### Custom feed generators

If you need to produce a custom feed format, you’ve got a couple of options.

If the feed format is totally custom, you’ll want to subclass
`SyndicationFeed` and completely replace the `write()` and
`writeString()` methods.

However, if the feed format is a spin-off of RSS or Atom (i.e. [GeoRSS](https://georss.org), Apple’s
[iTunes podcast format](https://help.apple.com/itc/podcasts_connect/#/itcb54353390), etc.), you’ve got a better choice. These types of
feeds typically add extra elements and/or attributes to the underlying format,
and there are a set of methods that `SyndicationFeed` calls to get these extra
attributes. Thus, you can subclass the appropriate feed generator class
(`Atom1Feed` or `Rss201rev2Feed`) and extend these callbacks. They are:

**`SyndicationFeed.root_attributes(self)`**

  Return a `dict` of attributes to add to the root feed element
  (`feed`/`channel`).

**`SyndicationFeed.add_root_elements(self, handler)`**

  Callback to add elements inside the root feed element
  (`feed`/`channel`). `handler` is an
  [`XMLGenerator`](https://docs.python.org/3/library/xml.sax.utils.html#xml.sax.saxutils.XMLGenerator) from Python’s built-in SAX library;
  you’ll call methods on it to add to the XML document in process.

**`SyndicationFeed.item_attributes(self, item)`**

  Return a `dict` of attributes to add to each item (`item`/`entry`)
  element. The argument, `item`, is a dictionary of all the data passed to
  `SyndicationFeed.add_item()`.

**`SyndicationFeed.add_item_elements(self, handler, item)`**

  Callback to add elements to each item (`item`/`entry`) element.
  `handler` and `item` are as above.

> **Warning**
>
> If you override any of these methods, be sure to call the superclass methods
> since they add the required elements for each feed format.

For example, you might start implementing an iTunes RSS feed generator like so:

```
class iTunesFeed(Rss201rev2Feed):
    def root_attributes(self):
        attrs = super().root_attributes()
        attrs["xmlns:itunes"] = "http://www.itunes.com/dtds/podcast-1.0.dtd"
        return attrs

    def add_root_elements(self, handler):
        super().add_root_elements(handler)
        handler.addQuickElement("itunes:explicit", "clean")
```

There’s a lot more work to be done for a complete custom feed class, but the
above example should demonstrate the basic idea.
