DEV Community

Cover image for Building an RSS Feed for a Django + React Portfolio (With a Styled Browser View)
Vicente G. Reyes
Vicente G. Reyes

Posted on • Originally published at vicentereyes.org

Building an RSS Feed for a Django + React Portfolio (With a Styled Browser View)

RSS isn't dead. Developers still use feed readers, and having a proper /rss.xml or /blog/rss URL is a small but meaningful signal that your site is a real publication. My portfolio runs on a split stack — a React SPA on Vercel and a Django REST API on a separate domain — so adding RSS turned out to be more interesting than I expected. Here's exactly what I built, the bugs I hit along the way, and the final result.

The Setup

  • Frontend: React + Vite, deployed on Vercel at vicentereyes.org
  • Backend: Django (cookiecutter-django), deployed at backend.vicentereyes.org
  • Goal: RSS feed available at two URLs:
    • vicentereyes.org/rss.xml — the classic URL people expect
    • vicentereyes.org/blog/rss — the canonical feed linked from the blog page

The Django Feed

Django ships with a syndication framework that makes building RSS feeds straightforward. I created blogs/feeds.py:

from io import StringIO

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

from .models import BlogPost

_SITE = "https://www.vicentereyes.org"
_FEED_URL = f"{_SITE}/blog/rss"
_XSL_URL = f"{_SITE}/rss.xsl"


class StyledRssFeed(Rss201rev2Feed):
    def write(self, outfile, encoding):
        buf = StringIO()
        super().write(buf, encoding)
        xml = buf.getvalue()
        # Insert XSL PI after the <?xml ...?> declaration line
        split = xml.index("\n") + 1
        outfile.write(xml[:split])
        outfile.write(f'<?xml-stylesheet type="text/xsl" href="{_XSL_URL}"?>\n')
        outfile.write(xml[split:])


class LatestBlogPostsFeed(Feed):
    feed_type = StyledRssFeed
    title = "Vicente Reyes - Blog"
    link = f"{_SITE}/blog"
    description = "Latest posts from Vicente Reyes"

    def feed_url(self):
        return _FEED_URL

    def items(self):
        return BlogPost.objects.order_by("-date_published")

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

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

    def item_link(self, item):
        return f"{_SITE}/blog/{item.slug}-{item.uid}"

    def item_pubdate(self, item):
        return item.date_published

    def item_author_name(self, item):
        return item.author_name
Enter fullscreen mode Exit fullscreen mode

Top comments (0)