Django: indicate which item in the selected menu

I'm sure I saw this question before in Stack Overflow, but I could not find it in my life, so nothing happens here.

I have a regular Django menu that uses {% url %} tags and static names for menu items. Now I want to have a different style for the selected menu item. But the menu is displayed in the base template, so how can I determine which menu item it is?

+4
source share
4 answers

You could do this with some ugly template code, but the best globally known way is to use a CSS selector. This allows CSS to do all the work automatically for you.

Here's how it works:

You simply add an identifier to your body depending on which page you are on. Then in css you do something like this:

 #section-aboutme #nav-aboutme, #section-contact #nav-contact /* ... put one of these per body/menu item ... */ { font-color: red; } 

You put nav-aboutme and nav-contact identifiers for each of your menu items.

The style will be automatically selected by CSS depending on which body body it is inside.

+6
source

I usually do this as Brian suggested, but to write the template that the designer gave me, which used the more general class="selected" method, I wrote {% nav%} .

Your HTML navigation template will look something like this:

 {% block nav %} <ul class="nav"> <li{% if nav.home %} class="selected"{% endif %}><a href="/">Home</a></li> <li{% if nav.about %} class="selected"{% endif %}><a href="/about/">About</a></li> </ul> {% endblock %} 

To configure navigation in a child template, follow these steps:

 {% include "base.html" %} {% load nav %} {% block nav %} {% nav "about" %} {{ block.super }} {% endblock %} 
+2
source

What about the custom tag that you use to create your navigation item?

Below is the name of the URL for which the navigation item should be created, and the text that it should display. It generates a li tag with the class "selected" if the named URL matches the current URL (requires 'django.core.context_processors.request' in your TEMPLATE_CONTEXT_PROCESSORS ). Inside li, it generates a tag with a URL outline specified by url_name . It has the contents indicated by contents .

Obviously, this can be modified to create different layouts for the navigation item, if required.

The rest can be done using CSS.

Benefits:

  • Easy to use

  • Small code required

  • DRY

  • Can be made more flexible

Disadvantages:

  • Requires 'django.core.context_processors.request'

  • Required URLs, for example. urlpatterns = patterns('django.views.generic.simple', ... (r'^$', 'direct_to_template', {'template': 'index.html'}, 'index'), ... ) . This can be done differently (e.g. pass a url).

  • It does not cope with pages that are not exactly equal to the specified one, and therefore will not apply the selected class to whether it is on the page below in the hierarchical URL hierarchy. For example, if I am in / products /, it will highlight the nav element pointing to / products /. If I included / products / myProduct /, it will not highlight / products / link. It can be encoded, but it forces people to use reasonable URLs. For example, change the destination of additionalAttrs to additionalAttrs = ' class=selected' if (context['request'].path.startswith(path) and path != '/') or (context['request'].path == path) else '' .

code:

 from django import template from django.core.urlresolvers import reverse register = template.Library() class NavNode(template.Node): def __init__(self, url_name, contents): self.url_name = url_name self.contents = contents def render(self, context): path = reverse(self.url_name) additionalAttrs = ' class=selected' if path == context['request'].path else '' return '<li'+additionalAttrs+'><a href="'+path+'">'+self.contents+'</a></li>' @register.tag def nav_link(parser, token): bits = token.split_contents() if len(bits) == 3: contents = bits.pop() url_name = bits.pop() else: raise template.TemplateSyntaxError, "%r tag requires a single argument" % bits[0] if contents[0] == contents[-1] and contents[0] in ('"', "'"): contents = contents[1:-1] return NavNode(url_name, contents) 
+2
source

You can pass request.path to your template

 from django.shortcuts import render_to_response from django.template import RequestContext return render_to_response('templ.html', {'page':request.path}, context_instance=RequestContext(request)) 

then use the ugly template tag to add a CSS class to your menu item

+1
source

All Articles