Django RSS Feed Tutorial

Django comes with a built-in syndication feed for dynamically generating RSS (Really Simple Syndication) or Atom feeds.

These feeds contain recently updated content on a website, and users can subscribe to them using a feed aggregator like Feedly. For example, the RSS feed for this website is located at https://learndjango.com/feed/rss.

Adding a Django syndication feed takes only a few minutes. All we need to do is create a dedicated file--often called feeds.py--that extends the built-in Feed class and then link it to a URL path. That's it!

Models, Views, URLs

For demonstration purposes, here are the models, views, and URLs for a tutorials app similar to what you see on this website. We'll use this as the basis for adding a feed in the next section.

The models file would look as follows:

# tutorials/models.py
from django.contrib.auth import get_user_model
from django.db import models
from django.urls import reverse

class Tutorial(models.Model):
    author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    description = models.CharField(max_length=200)
    slug = models.SlugField(null=False, unique=True)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_live = models.BooleanField(default=False)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('tutorial_detail', kwargs={'slug': self.slug})

    class Meta:
        ordering = ['-updated_at']

The views file would support a list page of all tutorials and a detail page for each.

# tutorials/views.py
from django.views.generic import ListView, DetailView

from .models import Tutorial

class TutorialListView(ListView):
    model = Tutorial
    context_object_name = 'tutorial_list'
    template_name = 'tutorials/tutorial_list.html'


class TutorialDetailView(DetailView): 
    model = Tutorial
    context_object_name = 'tutorial'
    template_name = 'tutorials/tutorial_detail.html'

And the existing URLs path would look something like this:

# tutorials/urls.py
from django.urls import path

from .feeds import TutorialFeed
from .views import TutorialListView, TutorialDetailView

urlpatterns = [
    path('<slug:slug>', TutorialDetailView.as_view(), name='tutorial_detail'),
    path('', TutorialListView.as_view(), name='tutorial_list'),
]

The overwhelming majority of websites have a similar pattern with a model, a view containing list and detail views, and two URL paths.

Feeds.py

To add RSS or Atom feeds to this app, we need to create a Feed class somewhere and add it to our URL. If you want multiple feeds, doing this within a specific app might make sense. However, if you intend to have one main feed for a project, adding it to the project-level directory is a good idea. That's what we'll do here.

The larger project for this Tutorials app is called django_project. Therefore we will create a new file called django_project/feeds.py in the project-level directory. Here are the contents of the file:

# django_project/feeds.py
from django.contrib.syndication.views import Feed
from django.template.defaultfilters import truncatewords

from tutorials.models import Tutorial


class RssTutorialsFeeds(Feed):
    title = "Tutorials"
    link = "/latesttutorials/"
    description = "Recent free tutorials on LearnDjango.com."

    def items(self):
        return Tutorial.objects.order_by("-updated_at")[:100]

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

    def item_description(self, item):
        return truncatewords(item.content, 30)

    def item_lastupdated(self, item):
        return item.updated_at

This Feeds file starts by importing the Feed class and the template filter truncatewords at the top. Next, we also import the Tutorial model from the tutorials app.

We define our custom feed by subclassing the Feed class and providing a name, RssTutorialsFeeds here. The title, link, and description are required RSS elements.

The meat of the feed is the following three methods:

URLS.py

The second step is to create a URL path for the feed in the project-level urls.py file. We need to import our custom feed class, RssTutorialsFeeds, and provide it a new URL pattern.

# django_project/urls.py
from django.contrib import admin
from django.urls import path, include

from .feeds import RssTutorialsFeeds  # new

urlpatterns = [
    path('admin/', admin.site.urls),
    path('tutorials/', include('tutorials.urls')),
    path('feed/rss', RssTutorialsFeeds(), name="tutorial_feed"),  # new

Navigate to http://127.0.0.1:8000/feed/rss in your web browser, and the RSS feed will be there listing all included tutorials (make sure you have added some to your admin for this example to work!)

In Chrome, you will see the XML code for the RSS feed directly, and in Safari, it will ask you to install an RSS feed reader. The free Fluent app is a good choice and supports Linux, macOS, and Windows.

Navbar

The last step is notifying your users about the RSS feed somehow, usually in the header or footer of your website. You can use the named URL, tutorial_feed, to do this. Something like the below:

<a href="{% url 'tutorial_feed' %}">RSS Feed</a>

Atom

Django allows you to publish either an RSS feed, an Atom feed, or both. To add Atom, we can subclass RssTutorialsFeeds to something different.

# django_project/feeds.py
from django.contrib.syndication.views import Feed
from django.template.defaultfilters import truncatewords
from django.utils.feedgenerator import Atom1Feed  # new

from tutorials.models import Tutorial


class RssTutorialsFeeds(Feed):
    title = "Tutorials"
    link = "/latesttutorials/"
    description = "Recent free tutorials on LearnDjango.com."

    def items(self):
        return Tutorial.objects.order_by("-updated_at")[:100]

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

    def item_description(self, item):
        return truncatewords(item.content, 30)

    def item_lastupdated(self, item):
        return item.updated_at


class AtomSiteNewsFeed(RssTutorialsFeeds):  # new
    feed_type = Atom1Feed
    subtitle = RssTutorialsFeeds.description

Then we update the URLconf.

# django_project/urls.py
from django.contrib import admin
from django.urls import path, include

from .feeds import RssTutorialsFeeds  # new

urlpatterns = [
    path('admin/', admin.site.urls),
    path('tutorials/', include('tutorials.urls')),
    path('feed/atom', RssTutorialsFeeds(), name="tutorial_feed"),  # new

In your web browser, navigate to http://127.0.0.1:8000/feed/atom to see the Atom feed.

Next Steps

As a batteries-included web framework, Django comes with many built-in features to help. For example, you can add a dynamically-generated sitemap. And if you want to add a favicon to your project, here is a Django Favicon tutorial to help.

Join My Newsletter

Subscribe to get the latest tutorials/writings by email.

    No spam. Unsubscribe at any time.