A few months ago, I described a Django template tag that I wrote to identify the currently active page.
At the time, I was satisfied with my solution, and I must say that it worked perfectly for all these months. The one thing I didn’t like about it though was that it wasn’t DRY. I had to specify an regular expression in the tag that would identify the current page. Those regexes were usually a copy of the ones in my urls.py file. This caused me some head scratching a couple of times when I changed a URL regex in urls.py, but forgot to change it in my _nav.html template.
Today, I took the time to remedy the situation and I am satisfied enough with the result to share it.
import re
from django.core.urlresolvers import RegexURLResolver
from project.app import urls
@register.simple_tag
def active(request, view='', pattern=''):
'''
Return 'active' if *pattern* matches *request.path* (the current location
in the browser). The empty string is returned otherwise. The pattern is
either given by the user or taken from the URLconf.
*request* (required): an HttpRequest object
*view* (optional): a view name
*pattern* (optional): a regular expression string
'''
path = request.path[1:] # Strip the leading /
if view != '':
for urlpattern in urls.urlpatterns:
# Skip include()s, they don't have the _callback_str attribute.
if isinstance(urlpattern, RegexURLResolver):
continue
if view == urlpattern._callback_str:
pattern = urlpattern.regex
break
if pattern == '':
return ''
if re.search(pattern, path):
return 'active'
else:
return ''
active takes two arguments: a request object and either a view name or a regex. If a view string is given, the function will try to find the matching regex in the urls module. If none can be found, the empty string is returned. If a regex pattern is given, this will be used to test the current path. This parameter exists to make sure that you can use any regular expression if you so desire. Leaving both parameters blank will return the empty string.
I hope this helps you.
May 7, 2008 at 4:45 pm |
any thoughts on making this work with dynamic URLs? I’ve tried to retrofit the django url tag, but I just don’t know enough python. Great work!
October 3, 2008 at 1:36 pm |
not working with the latest version…
need to import template
from django import template
and
register = template.Library()
And there are afew more problems am trying to figure out…
gr,
D.
August 27, 2009 at 2:43 am |
For those of you wishing for a Django SVN ready version of this…
place in /templatetags/
import re
from django import template
from django.core.urlresolvers import RegexURLResolver
from project.app import urls
register = template.Library()
@register.simple_tag
def active(request, view=”, pattern=”):
”’
Return ‘active’ if *pattern* matches *request.path* (the current location
in the browser). The empty string is returned otherwise. The pattern is
either given by the user or taken from the URLconf.
*request* (required): an HttpRequest object
*view* (optional): a view name
*pattern* (optional): a regular expression string
”’
path = request.path[1:] # Strip the leading /
if view != ”:
for urlpattern in urls.urlpatterns:
# Skip include()s, they don’t have the _callback_str attribute.
if isinstance(urlpattern, RegexURLResolver):
continue
if view == urlpattern._callback:
pattern = urlpattern.regex
break
if pattern == ”:
return ”
if re.search(pattern, path):
return ‘active’
else:
return ”