On several occasions, I (and the templaters on my team) have needed a way to do datetime comparisons from within a template. The first example is testing if the pub_date on an object is today. Usually, I just end up writing a helper method on the model to do this; something like is_today. However, we've run into several instances where this wasn't possible or it would have just been too much of a mess to write these helper methods on every model. I then decided to create a little templatetag to take care of this for me.
The first idea was to just create a get_today tag that would return the name of today at a string. But thinking into further, I decided to make it so it'd return any form of datatime for today by accepting a format string. For instance, the following example would fetch what I wanted earlier; the name of today at a string.
{% get_now:"l" as var_name %}
This is obviously only the tip of what you can return. You can return any form of datetime.now() by just passing it a format string. A reference for this can be found here.
This all seems simple enough, but that's because it really is! I don't suppose there's any easier way to explain it than just to show the code.
from django.core import template
from django.utils.dateformat import format
import datetime
import re
register = template.Library()
### Templates Tags
class GetNow(template.Node):
def __init__(self, format_string, var_name):
self.format_string = format_string
self.var_name = var_name
def render(self, context):
context[self.var_name] = format(datetime.datetime.now(), self.format_string)
return ''
def get_now(parser, token):
"""
Returns a string of now formated as specified.
Syntax::
{% get_now as [var_name] %}
"""
r1 = re.compile('[\"|\'](.+)[\"|\']') # format string regex
r2 = re.compile('as (.+)') # var_name regex
format_string = r1.findall(token.contents)
var_name = r2.findall(token.contents)
bits = token.contents.split()
if format_string and var_name:
return GetNow(format_string[0], var_name[0])
if not var_name:
raise template.TemplateSyntaxError, "'%s' tag requires a variable name to be given" % bits[0]
if not format_string:
raise template.TemplateSyntaxError, "'%s' tag requires a format string like 'jS F Y H:i'" % bits[0]
register.tag(get_now)
The only thing special about this tag is that I decided to use regular expressions to pick apart the token instead of relying on the standard bit[n] technique. This was all because normally, the token consists of full words, but in this tag, we need to pull the format string which includes spaces.
The rest of the logic should all be pretty self explanatory. I'll leave you with that!
Cheers!
Posted by Sean Stoops on March 8, 2008
Comments
No one has said anything yet...