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:
items
retrieves the objects for the feed; in this case the last 100 sorted byupdated_at
.item_title
returns thetitle
item_description
returns thedescription
truncated to 30 wordsitem_lastupdated
returns theupdated_at
timestamp
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.