Martin Geber
Martin is student at EUFH, Cologne, DE
working casually at DataCollect & EWE
who loves economies, web-technology
and all things J.K. Rowling.
Learn More.
It is quite typical for Wordpress-blogs to have all archives in the sidebar. For example "August 2005, September 2005", all linked back to the archives pages. Django, sadly, doesn't have something by default to generate these archive links dynamically.
There is another reason, why people, should want this ability, even though they don't want these links in their sidebar: the <link rel="archives" />-tags. In case you're not interested in this HTML-tag, just ignore the following paragraphs and skip directly to the source code.
<link rel="archives" />-HTML-TagI love one special little HTML-Tag, which isn't yet supported by any of the usual browsers: the <link>-tag. There is one great relation (rel), which provides the information about all archives the current website hosts. As Django doesn't provide something like that, I wrote a templatetag, which adds the <link rel="archives" />-tag. (I'm not interested in the sidebar at all, but my tag should have the ability, to do this job too.)
<link>-tag worksThe <link>-tag takes usually three attributes:
archive, which means this link holds an overview of contents.
Notice: The <link>-tag belongs into the <head>-tag.
<link rel="archives" />Like said above it enables you to tell the browser, user and of course search engines, where your archives are located. So when someone enters your website, s/he directly sees all important overview pages at once.
rel="" are available?There are various other relations of this tag available, here is a list of the most important:
<link rel="author" href="/about/" title="Martin Geber" />
up would than mean to jump to the album, the photo belongs to.
<link rel="start" href="/" title="Homepage" />
I guess there are even more, but these are the most important to provide a great browsing experience for the user. (See the last chapter for more information on that.)
Basically it is possible to provide archives of all your contents, photos, blogentries, or bookmarks. So the templatetag must be very flexible. Hopefully it really is.
If you know, how to set-up a template tag in Django, skip to the next headline. Otherwise, do as follows:
Create a folder called templatetags into an existing application, or start a new application, which you have to include into your INSTALLED_APPS-variable in the settings.py. Create a new file there, e.g. taglib.py. That's it.
This is the Python source code of the template tag, which will be registered to get_archives:
from django.template import Library, Node, TemplateSyntaxError from django.db.models import get_model from django.db import connection register = Library() class ContentArchives(Node): """ Retrieve an monthly archive listing, based on the a model of your decision. Of course you can format the output completely. When you use HTML as format please note that you should use single quotes ``'`` around the format instead the usual double quote ``"``. The format string can take these "variables", used like in Python (``%(variable)s``): * ``nicedate`` -- SQL-DateFormat string "%M %Y", e.g. "August 2007". * ``name`` -- The plural verbose name, which was defined in the ``Meta`` class by the attribute ``verbose_name_plural``. If you use i18n, this will also be translated automaticly. * ``year`` -- Year of the archive, four digits. * ``month`` -- Month of the archive, two digits. * ``count`` -- Number of nodes in the current archive. You should really use ``name`` as variable, especially when you use this template tag for more than one model. Otherwise, it is possible that you have "August 2005" twice as title... Syntax:: {% get_archives [object] [datefield] with [urlformat] %} Example:: {% get_archives weblog.Entry pub_date with '<link rel="archives" title="%(name)s %(nicedate)s (%(count)s)" href="/weblog/%(year)s/%(month)s/" />' %} Example Output:: <link rel="archives" title="Blog Entries August 2007 (1)" href="/weblog/2007/08/" /> <link rel="archives" title="Blog Entries November 2006 (1)" href="/weblog/2006/11/" /> <link rel="archives" title="Blog Entries July 2006 (1)" href="/weblog/2006/07/" /> *Please Note:* ``%(name)s`` will be translated, in case you use I18N. """ def __init__(self, model, field, htmlformat): self.field, self.htmlformat = field, htmlformat self.model_table = model.replace('.', '_').lower() self.model = get_model(*model.split('.')) def render(self, context): cursor = connection.cursor() try: from MySQLdb import OperationalError except ImportError: pass try: cursor.execute('SELECT DATE_FORMAT(' + self.field + ', "%M %Y") AS date_title, DATE_FORMAT(' + self.field + ', "%Y") AS year, DATE_FORMAT(' + self.field + ', "%m") AS month,' + 'COUNT(*) as num FROM ' + self.model_table + ' GROUP BY date_title ORDER BY year DESC, month DESC') except OperationalError: raise TemplateSyntaxError('get_archives tag seems to have gotten wrong arguments. '+ 'does the table "%s" has a field "%s"?' % (self.model_table, self.field)) archives = cursor.fetchall() html_archive_links = '' for archive in archives: html_archive_links += self.htmlformat % {'nicedate': archive[0], 'year': archive[1], 'month': archive[2], 'count': archive[3], 'name': self.model._meta.verbose_name_plural} return html_archive_links def get_archives(parser, token): bits = token.split_contents() if len(bits) != 5: raise TemplateSyntaxError('get_archives tag takes exactly four arguments') if bits[3] != 'with': raise TemplateSyntaxError('third argument to get_archives tag must be "with"') return ContentArchives(bits[1], bits[2], bits[4][1:-1]+"\n\t") get_archives = register.tag(get_archives)
Like written in the Docstring of the ContentArchives-class, you can define the object, you want to use as archives. It must have a date-field, which will be given as second parameter to the template tag. The third parameter, or fourth if you count with as parameter, is the format you want to print the archives:
{% get_archives weblog.Entry pub_date with '<link rel="archives" title="%(name)s %(nicedate)s (%(count)s)" href="/weblog/%(year)s/%(month)s/" />' %}
You see that you are able to either use the described <link rel="archives" />-tag or any other link, often used in the sidebar. This would look like something like this:
{% get_archives weblog.Entry pub_date with '<a href="/weblog/%(year)s/%(month)s/" title="%(name)s %(nicedate)s (%(count)s)">%(nicedate)s</a>' %}
<link>-tagFirefox doesn't have by default the ability to make use of the <link>-tags, but you can give it a little help by using this extension: Link Widgets. Here is a screen shot of it in action:
You see that you have (when you click at the Folder-Button) information on archives and on the author.
<link rel="next" />-tag and <link rel="prev" />-tag.
<link rel="up" />-tag. I decided that upwards mean the day the article was published.
<link rel="start" />.
Now, after you learned how to add these <link>-tags I hope it is clear how to use them practical.
Python Code is Poetry
© Copyright 1987-2008
Martin Geber
Django | XHTML 1.1 | CSS | Imprint
Kevin commented, on December 14, 2007 at 4:05 a.m.:
Don't forget to also make an init.py file (it can be blank) in the templatetags directory. Otherwise, Python is not likely to find your "taglib" module.