Navigation in django
I've just done my first little webapp in django and I love it. I'm about to start on converting an old production PHP site into django and as part its template, there is a navigation bar.
In PHP, I check each nav option's URL against the current URL, in the template code and apply a CSS class if they line up. It's horrendously messy.
Is there something better for django or a good way of handling the code in the template?
To start, how would I go about getting the current URL?
You do not need an if to do that, have a look at the following code:
tags.py
@register.simple_tag
def active(request, pattern):
import re
if re.search(pattern, request.path):
return 'active'
return ''
urls.py
urlpatterns += patterns('',
(r'/$', view_home_method, 'home_url_name'),
(r'/services/$', view_services_method, 'services_url_name'),
(r'/contact/$', view_contact_method, 'contact_url_name'),
)
base.html
{% load tags %}
{% url 'home_url_name' as home %}
{% url 'services_url_name' as services %}
{% url 'contact_url_name' as contact %}
<div id="navigation">
<a class="{% active request home %}" href="{{ home }}">Home</a>
<a class="{% active request services %}" href="{{ services }}">Services</a>
<a class="{% active request contact %}" href="{{ contact }}">Contact</a>
</div>
that's it.
for implementation details have a look at:
gnuvince.wordpress.com
110j.wordpress.com
I use template inheritance to customize navigation. For example:
base.html
<html>
<head>...</head>
<body>
...
{% block nav %}
<ul id="nav">
<li>{% block nav-home %}<a href="{% url 'home' %}">Home</a>{% endblock %}</li>
<li>{% block nav-about %}<a href="{% url 'about' %}">About</a>{% endblock %}</li>
<li>{% block nav-contact %}<a href="{% url 'contact' %}">Contact</a>{% endblock %}</li>
</ul>
{% endblock %}
...
</body>
</html>
about.html
{% extends "base.html" %}
{% block nav-about %}<strong class="nav-active">About</strong>{% endblock %}
I liked the cleanness of 110j above so I took most of it and refactored to solve the 3 problems I had with it:
- the regular expression was matching the 'home' url against all others
- I needed multiple URLs mapped to one navigation tab, so I needed a more complex tag that takes variable amount of parameters
- fixed some url problems
Here it is:
tags.py:
from django import template
register = template.Library()
@register.tag
def active(parser, token):
args = token.split_contents()
template_tag = args[0]
if len(args) < 2:
raise template.TemplateSyntaxError, "%r tag requires at least one argument" % template_tag
return NavSelectedNode(args[1:])
class NavSelectedNode(template.Node):
def __init__(self, patterns):
self.patterns = patterns
def render(self, context):
path = context['request'].path
for p in self.patterns:
pValue = template.Variable(p).resolve(context)
if path == pValue:
return "active" # change this if needed for other bootstrap version (compatible with 3.2)
return ""
urls.py:
urlpatterns += patterns('',
url(r'/$', view_home_method, {}, name='home_url_name'),
url(r'/services/$', view_services_method, {}, name='services_url_name'),
url(r'/contact/$', view_contact_method, {}, name='contact_url_name'),
url(r'/contact/$', view_contact2_method, {}, name='contact2_url_name'),
)
base.html:
{% load tags %}
{% url home_url_name as home %}
{% url services_url_name as services %}
{% url contact_url_name as contact %}
{% url contact2_url_name as contact2 %}
<div id="navigation">
<a class="{% active request home %}" href="home">Home</a>
<a class="{% active request services %}" href="services">Services</a>
<a class="{% active request contact contact2 %}" href="contact">Contact</a>
</div>