djangoproject.com | nginx.org | python.org | linux.com
version seven.
  http://demongin.org
demongin.org - Combined RSS Feeds from Multiple Models in <i>Django</i>

Combined RSS Feeds from Multiple Models in Django

I push a minor update to the site and describe how I did it.


Friday, 2009-10-30 | demongin.org, Django, Programming, Testing

There seems to be an alien pubic hair in my gin. Never seen it before in my life! Have you?

Artie's screen cap of the malfunctioning RSS sortSome short front-matter before we begin:

  1. I just pushed an update to the site that fixes how the RSS feed was sorting posts and I'd like to issue a blanket mea culpa for any redundancy or other miscellaneous weirdness that anyone might experience with his RSS reader.
  2. I'd like to issue a formal shout out to Artie Jordan and Peter Celauro for the QA that triggered this update.
Those remarks having been made, I'd like to describe (in brief) what I just fixed in the RSS feed for the site and how I fixed it.

Artie noticed in his RSS client that regular blog posts and media blog posts were apparently not sorted by date. Well, that's not totally accurate: they were sorted by date, but they weren't combined. Basically, you'd see the 10 most recent blog posts and then the 10 most recent media blog posts.

The problem, I rapidly discovered, was some laziness on my part when configuring the feed the first time around. You see, I basically pulled the RSS code straight from the Django tutorial site and used a real quick and dirty itertools.chain() line to combine the two feeds. Here's the original RSS code:
class LatestEntries(Feed):
    domain = 'demongin.org'
    title = "demongin.org"
    link = "/blog/"
    description = "Latest blog posts from http://demongin.org."
    def items(self):
        results = itertools.chain(
            Post.objects.all().order_by('-pub_date')[:10],
            MediaPost.objects.all().order_by('-pub_date')[:10],
        ) 
        return results
You can see what was happening: I was doing two queries, and chaining them together, forming one data stream with the itertools.chain function. And this is what lead to the weird malfunction.

The solution ended up being simpler than I would have imagined: I basically used python's built-in sorted function and a drop-dead simple lambda:
class LatestEntries(Feed):
    domain = 'demongin.org'
    title = "demongin.org"
    link = "/blog/"
    description = "Latest blog posts from http://demongin.org."

    def items(self):    ## thanks to Artie for the QA on this one.
        results = itertools.chain(
            Post.objects.all().order_by('-pub_date')[:5],
            MediaPost.objects.all().order_by('-pub_date')[:5],
        ) 
        
        return sorted(results, key=lambda x: x.pub_date, reverse=True)
So you can see, I keep my itertools.chain() pretty much just the way I had it, except instead of returning the unsorted data stream, I sort the stream using sorted's "key" argument by passing a simple lambda where the sort keys on "pub_date".

Pretty cool.