How to add Atom feeds for each django-plugin-blog tag
6 January 2025
As mentioned in an earlier post, this blog is built using django-plugin-blog. By default, django-plugin-blog outputs a single Atom feed (at /blog/feed/
) which lists the five most recent posts.
For reference, see django-plugin-blog's views.py
and __init__.py
files:
from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Atom1Feed
class BlogFeed(Feed):
...
def urlpatterns():
from .views import BlogFeed
return [
path(f"{blog}/feed/", BlogFeed(), name="django_plugin_blog_feed"),
]
However, I also wanted feeds for each blog post tag ('django', 'python', etc.). Django's syndication framework, which django-plugin-blog already uses, makes it easy to add both more Atom feeds and, if required, RSS feeds.
I implemented the feed code via a new 'blog' app:
python manage.py startapp blog
Therein, the key file is views.py
, which features a BlogTagFeed
class that:
- subclasses Django's syndication
Feed
class - declares its type as Atom (
Atom1Feed
) - defines methods which return various feed and item attributes
Whilst some of the code is specific to django-plugin-blog, such as getting Tag
data, the overall approach is universal.
from django.conf import settings
from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Atom1Feed
from django_plugin_blog.models import Tag
class BlogTagFeed(Feed):
"""Atom feed of latest blog entries for each tag ('django', 'python', etc.)."""
feed_type = Atom1Feed
def get_object(self, request, slug):
return Tag.objects.get(slug=slug)
def title(self, obj):
title = getattr(settings, "DJANGO_PLUGIN_BLOG_FEED_TITLE", None) or obj.get_host()
return f"{title}: Posts tagged '{obj.name}'"
def link(self, obj):
return f"/blog/tag/{obj.slug}/"
def items(self, obj):
return obj.entry_set.filter(is_draft=False).order_by("-created")[:10]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.summary_rendered
def item_link(self, item):
return f"/blog/{item.created.year}/{item.slug}/"
def item_author_name(self, item):
return (
", ".join([a.get_full_name() or str(a) for a in item.authors.all()]) or None
)
def get_feed(self, obj, request):
feedgen = super().get_feed(obj, request)
feedgen.content_type = "application/xml; charset=utf-8"
return feedgen
Having created the new feeds, I then updated the site's URLconf. For simplicity, I used the same /feed
path naming convention as django-plugin-blog.
urlpatterns = [
path('blog/tag/<slug:slug>/feed/', BlogTagFeed()),
]
urlpatterns = [
path('', include('blog.urls')),
]
And that's it. Atom feeds are now available for every blog tag (such as 'django').
Code
For the complete blog app code, see https://github.com/input/lm.