This afternoon I made a small update to the site, adding RSS feeds for every tag in the database. So now, if you like, you can subscribe to the latest content about python or music or media or anything else I've got. The feeds are found in the hidden autodiscovery tag at the top of the page, so you'll have to use the pulldown in your browser's URL bar to get at them. But they're there.
Thanks to a number of shortcuts in Django's feed syndication framework and the excellent django-tagging, it's pretty easy to put something like this together. Here's how I did it.
First, in my blog app's feeds.py file:
<div class="source"><pre><span></span><span class="c1"># Feeds</span> <span class="kn">from</span><span class="w"> </span><span class="nn">django.contrib.syndication.feeds</span><span class="w"> </span><span class="kn">import</span> <span class="n">Feed</span><span class="p">,</span> <span class="n">FeedDoesNotExist</span> <span class="c1"># Models</span> <span class="kn">from</span><span class="w"> </span><span class="nn">tagging.models</span><span class="w"> </span><span class="kn">import</span> <span class="o">*</span> <span class="c1"># Helpers</span> <span class="kn">from</span><span class="w"> </span><span class="nn">django.core.exceptions</span><span class="w"> </span><span class="kn">import</span> <span class="n">ObjectDoesNotExist</span> <span class="k">class</span><span class="w"> </span><span class="nc">TagFeed</span><span class="p">(</span><span class="n">Feed</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> The most recent content with a particular tag.</span> <span class="sd"> """</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_object</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">bits</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Fetch the Tag object.</span> <span class="sd"> """</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span> <span class="k">raise</span> <span class="n">ObjectDoesNotExist</span> <span class="k">return</span> <span class="n">Tag</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name__exact</span><span class="o">=</span><span class="n">bits</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">def</span><span class="w"> </span><span class="nf">title</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Set the feed title.</span> <span class="sd"> """</span> <span class="k">return</span> <span class="s2">"</span><span class="si">%s</span><span class="s2"> . tags . palewire"</span> <span class="o">%</span> <span class="n">obj</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="nf">description</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Set the feed description.</span> <span class="sd"> """</span> <span class="k">return</span> <span class="s2">"the latest tagged </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">obj</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="nf">link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Set the feed link.</span> <span class="sd"> """</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="p">:</span> <span class="k">raise</span> <span class="n">FeedDoesNotExist</span> <span class="k">return</span> <span class="sa">u</span><span class="s1">'/tags/</span><span class="si">%s</span><span class="s1">/'</span> <span class="o">%</span> <span class="n">obj</span><span class="o">.</span><span class="n">name</span> <span class="k">def</span><span class="w"> </span><span class="nf">items</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Fetch the latest 10 objects with a particular tag, which is passed as the `obj` argument.</span> <span class="sd"> """</span> <span class="c1"># Pull all the items with that tag.</span> <span class="n">taggeditem_list</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">items</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="c1"># Loop through the tagged items and return just the items with a pub_date attribute</span> <span class="n">object_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span><span class="o">.</span><span class="n">object</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">taggeditem_list</span> <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">i</span><span class="o">.</span><span class="n">object</span><span class="p">,</span> <span class="s1">'pub_date'</span><span class="p">,</span> <span class="kc">False</span><span class="p">)]</span> <span class="c1"># Now resort them by the pub_date attribute with the newest coming first</span> <span class="n">object_list</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">pub_date</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># And return the first ten.</span> <span class="k">return</span> <span class="n">object_list</span><span class="p">[:</span><span class="mi">10</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">item_link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Set the URL for each tagged item, using the url attribute we have on each of our models.</span> <span class="sd"> """</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="p">:</span> <span class="k">raise</span> <span class="n">FeedDoesNotExist</span> <span class="k">return</span> <span class="n">obj</span><span class="o">.</span><span class="n">url</span> </pre></div>I then added the new TagFeed class to my feed dictionary in the urls/feeds.py file. You can see it at the bottom there.
<div class="source"><pre><span></span><span class="c1"># urls</span> <span class="kn">from</span><span class="w"> </span><span class="nn">django.conf.urls.defaults</span><span class="w"> </span><span class="kn">import</span> <span class="o">*</span> <span class="c1"># Feeds</span> <span class="kn">from</span><span class="w"> </span><span class="nn">coltrane.feeds</span><span class="w"> </span><span class="kn">import</span> <span class="o">*</span> <span class="c1"># Feed index page</span> <span class="n">urlpatterns</span> <span class="o">=</span> <span class="n">patterns</span><span class="p">(</span><span class="s1">'django.views.generic'</span><span class="p">,</span> <span class="p">(</span><span class="sa">r</span><span class="s1">'^list/$'</span><span class="p">,</span> <span class="s1">'simple.direct_to_template'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'template'</span><span class="p">:</span> <span class="s1">'coltrane/feed_list.html'</span><span class="p">}),</span> <span class="p">)</span> <span class="c1"># RSS feeds mapped to URL slugs</span> <span class="n">feeds</span> <span class="o">=</span> <span class="p">{</span> <span class="c1"># Bundles</span> <span class="s1">'the-full-feed'</span><span class="p">:</span> <span class="n">FullFeed</span><span class="p">,</span> <span class="s1">'less-noise'</span><span class="p">:</span> <span class="n">LessNoise</span><span class="p">,</span> <span class="c1"># Singletons</span> <span class="s1">'posts'</span><span class="p">:</span> <span class="n">RecentPosts</span><span class="p">,</span> <span class="s1">'comments'</span><span class="p">:</span> <span class="n">RecentComments</span><span class="p">,</span> <span class="s1">'shouts'</span><span class="p">:</span> <span class="n">RecentShouts</span><span class="p">,</span> <span class="s1">'links'</span><span class="p">:</span> <span class="n">RecentLinks</span><span class="p">,</span> <span class="s1">'photos'</span><span class="p">:</span> <span class="n">RecentPhotos</span><span class="p">,</span> <span class="s1">'tracks'</span><span class="p">:</span> <span class="n">RecentTracks</span><span class="p">,</span> <span class="s1">'books'</span><span class="p">:</span> <span class="n">RecentBooks</span><span class="p">,</span> <span class="s1">'commits'</span><span class="p">:</span> <span class="n">RecentCommits</span><span class="p">,</span> <span class="s1">'tag'</span><span class="p">:</span> <span class="n">TagFeed</span><span class="p">,</span> <span class="p">}</span> <span class="c1"># Feed urlpattern</span> <span class="n">urlpatterns</span> <span class="o">+=</span> <span class="n">patterns</span><span class="p">(</span><span class="s1">''</span><span class="p">,</span> <span class="n">url</span><span class="p">(</span><span class="sa">r</span><span class="s1">'(?P<url>.*)/$'</span><span class="p">,</span> <span class="s1">'django.contrib.syndication.views.feed'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'feed_dict'</span><span class="p">:</span> <span class="n">feeds</span><span class="p">},</span> <span class="n">name</span><span class="o">=</span><span class="s1">'coltrane_feeds'</span><span class="p">),</span> <span class="p">)</span> <span class="o"></</span><span class="n">url</span><span class="o">></span> </pre></div>And finally added the URL to the autodiscovery portion of the head in my tag_detail.html template.
<div class="source"><pre><span></span>{% block extrarss %} <span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">"/feeds/tag/{{ tag }}/"</span> <span class="na">rel</span><span class="o">=</span><span class="s">"alternate"</span> <span class="na">title</span><span class="o">=</span><span class="s">"latest tagged {{ tag }}"</span> <span class="na">type</span><span class="o">=</span><span class="s">"application/rss+xml"</span><span class="p">/></span> {% endblock %} </pre></div>You can find my blog's entire codebase online here. And I always appreciate a good criticism. So if you see anything wrong, fire away.