This tag makes it easy to include menu or navigation bars in an application's pages, even in a 'tabbed' fashion. (The actual appearance is styled in CSS; this example uses UL tags that are then supposed to be styled by a "display: inline" attribute to be rendered as horizontal bars.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | from django import template
from django.conf import settings
from django.utils.translation import ugettext as _
class SimpleMenu(object):
"""
Stores a tree-like menu hierarchy, and renders it up to a chosen item
on request.
"""
def __init__(self, menulist):
"""
Initializes the class.
The menulist argument is a dictionary of menus. Each key is the menu
label; the corresponding value is a list of (item_label, urlname)
pairs. The 'urlname' is then looked up in the URL configuration in
order to correctly render the matching link. (See example below.)
"""
self.menus = menulist
def render(self, menu_name, depth=0, active=None):
"""
The render() method returns a HTML string suitable for use as a
menu bar on a given page.
menu_name: the label of a menu, as specified at class initialization.
depth (kw): an integer specifying how far into the tree this is being
rendered. Usually the render() method takes care of the whole menu,
but it may be occasionally useful to delegate a single sub-menu to the
SimpleMenu class. Note that this parameter only affects the CSS class.
active(kw): the active label, if any, in the menu.
"""
from django.core.urlresolvers import reverse
s = '<div class="menu depth%d"><ul>' % depth
for label, view in self.menus[menu_name]:
s += '<li class="%s"><a href="%s">%s</a></li>' % (['nonactive',
'active'][view==active], reverse(view), label)
return s + '</ul></div>'
menu = SimpleMenu(settings.MENUITEMS)
# Example:
# MENUITEMS = {
# 'root': ((_('Venues'), 'venue_menu'), (_('My account'), 'account_menu')),
# 'venue_menu': ((_('Browse'), 'venue_browse'), (_('New venue'), 'eatout-add-venue'),)
#}
class MenuNode(template.Node):
"""
The menu tag takes a menu path whose components are labels separated by spaces.
All the components from the first to the next-to-last are menu labels, and
they are going to be rendered as menu bars. Since they are seen as
sub-items, or (if you will) as nested tabs in a web page, each component
is also the active component in the previous menu.
The last component is not rendered as a menu, but it is taken to be the
active item in the last menu (that is, the next-to-last component).
"""
def __init__(self, menu_path):
self.menu_path = menu_path
def render(self, context):
# Item = (item, follower)
for i in range(len(self.menu_path)):
# Strip any single quotes from the string edges
self.menu_path = [s.rstrip('"\'').lstrip('"\'')
for s in self.menu_path]
self.context = context
# Render each couple: (1,2), (2,3), (3,4), ...
return ''.join([self._render_menu(self.menu_path[index],
active=self.menu_path[index+1], depth=index)
for index in range(len(self.menu_path)-1)])
def _render_menu(self, menu_name, active=None, depth=None):
"""
If the menu has its own template, then use the template. Otherwise,
ask its class to do the rendering.
"""
from django.template.loader import get_template
from django.template import TemplateDoesNotExist
try:
menu_template = get_template('menu/%s.html' % menu_name)
self.context['active'] = active
return menu_template.render(self.context)
except TemplateDoesNotExist:
return menu.render(menu_name, depth=depth, active=active)
def do_menu(parser, token):
menu_path = token.split_contents()
return MenuNode(menu_path[1:])
# Usage example:
# {% menu root venue_menu new_visit %}
# will render the 'root' menu with the 'venue_menu' item, if it exists, as
# active; then the 'venue_menu_ menu with the 'new_visit' item, if it
# exists, as active.
register.tag('menu', do_menu)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
MENUITEMS = { 'root': ((('Venues'), 'venue_menu'), (('My account'), 'account_menu')), 'venue_menu': ((('Browse'), 'venue_browse'), (('New venue'), 'eatout-add-venue'),) }
seems to be broken. When I add that to my settings file I get the following error:
File "manage.py", line 4, in <module> import settings # Assumed to be in the same directory. File "/home/sebastian/django_root/championsound/settings.py", line 144, in <module> 'root': ((('Venues'), 'venue_menu'), (('My account'), 'account_menu')), File "/usr/lib/python2.5/site-packages/django/utils/translation/init.py", line 61, in ugettext return real_ugettext(message) File "/usr/lib/python2.5/site-packages/django/utils/translation/init.py", line 31, in delayed_loader if settings.USE_I18N: File "/usr/lib/python2.5/site-packages/django/conf/init.py", line 28, in getattr self._import_settings() File "/usr/lib/python2.5/site-packages/django/conf/init.py", line 55, in _import_settings raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE EnvironmentError: Environment variable DJANGO_SETTINGS_MODULE is undefined.
I am importing ugettext as _
#
Please login first before commenting.