Python Developer and Educator
2008-09-21
I'm in the process of writing my own blog app (project 'belleville'), one that will eventually replace the Wordpress blog that this site is using, and one of the things I need is a templatetag for the sidebar that lists archive dates, grouped by month - it should look something like the "Archive" list just there to the right, or like this:
The problem is that the date field I have to work with is a MySQL datetime column:
created_at = models.DateTimeField(auto_now_add=True)
... and I only need a unique list of year-month values for all of my active posts.
import datetime
from django import template
from myentries.models import Post
register = template.Library()
def sidebar_date_list():
posts = Post.objects.filter(publish=1)
for post in posts:
post.month = str(post.created_at.year)+'-'+str(post.created_at.month).rjust(2, '0')
return {'posts': posts}
register.inclusion_tag('date_list.html')(sidebar_date_list)
This gives me a long list of all the existing dates in the format I need:
2008-09
2008-09
2008-09
2008-09
2008-09
2008-09
2008-08
2008-08
2008-08
2008-08
2008-08
2008-08
2008-07
2008-07
2008-07
2008-07
2008-07
2008-07
2008-07
2008-07
2008-07
2008-07
2008-07
2008-06
2008-06
2008-06
Then I can do the date grouping in the template using the Django's regroup tag:
{% if posts %}
<h2>Archive</h2>
<ul>
{% regroup posts by month as month_list %}
{% for month in month_list %}
<li><a href="/date/{{ month.grouper }}">{{ month.grouper }}</a></li>
{% endfor %}
</ul>
{% endif %}
def sidebar_date_list():
posts = Post.objects.filter(publish=1).order_by('-created_at')
month_list = []
for post in posts:
post.month = datetime.datetime(post.created_at.year, post.created_at.month, 1)
month_list.append(post.month)
months = set(month_list)
months = list(months)
months.sort(reverse=True)
return {'months': months}
register.inclusion_tag('date_list.html')(sidebar_date_list)
The month list looks like this:
[datetime.datetime(2008, 9, 1, 0, 0), datetime.datetime(2008, 9, 1, 0, 0), datetime.datetime(2008, 9, 1, 0, 0),
datetime.datetime(2008, 9, 1, 0, 0), datetime.datetime(2008, 9, 1, 0, 0), datetime.datetime(2008, 9, 1, 0, 0),
datetime.datetime(2008, 8, 1, 0, 0), datetime.datetime(2008, 8, 1, 0, 0), datetime.datetime(2008, 8, 1, 0, 0),
datetime.datetime(2008, 8, 1, 0, 0), datetime.datetime(2008, 8, 1, 0, 0), datetime.datetime(2008, 8, 1, 0, 0),
datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 7, 1, 0, 0),
datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 7, 1, 0, 0),
datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 7, 1, 0, 0),
datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 6, 1, 0, 0),
datetime.datetime(2008, 6, 1, 0, 0), datetime.datetime(2008, 6, 1, 0, 0)]
But converting the list to a set eliminates all the duplicate elements:
months = set(month_list)
set([datetime.datetime(2008, 6, 1, 0, 0), datetime.datetime(2008, 9, 1, 0, 0),
datetime.datetime(2008, 7, 1, 0, 0), datetime.datetime(2008, 8, 1, 0, 0)])
Then convert the set back to a list so it can be sorted:
months = list(months)
months.sort(reverse=True)
And you can iterate over that list in the template, it's just that simple:
{% if months %}
<h2>Archive</h2>
<ul>
{% for month in months %}
<li><a href="/date/{{ month|date:"Y-m" }}">{{ month|date:"Y-m" }}</a></li>
{% endfor %}
</ul>
{% endif %}
Contact: barbara@mechanicalgirl.com