Django CMS icon in menu - django

I am trying to show my uploaded icon on navigation but i guess, i am going through a wrong way.
this is my model that extended
class IconExtension(PageExtension):
image = models.ImageField(upload_to='icons')
extension_pool.register(IconExtension)
and this is my cms_toolbars.py file
#toolbar_pool.register
class IconExtensionToolbar(ExtensionToolbar):
# defines the model for the current toolbar
model = IconExtension
def populate(self):
# setup the extension toolbar with permissions and sanity checks
current_page_menu = self._setup_extension_toolbar()
# if it's all ok
if current_page_menu:
# retrieves the instance of the current extension (if any) and the toolbar item URL
page_extension, url = self.get_page_extension_admin()
if url:
# adds a toolbar item in position 0 (at the top of the menu)
current_page_menu.add_modal_item(_('Page Icon'), url=url,
disabled=not self.toolbar.edit_mode_active, position=0)
and this is my menu.html file
{% load menu_tags %}
{% for child in children %}
<li class="child{% if child.selected %} selected{% endif %}{% if child.ancestor %} ancestor{% endif %}{% if child.sibling %} sibling{% endif %}{% if child.descendant %} descendant{% endif %}">
<a href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">{{ child.get_menu_title }}
<img src="{{ child.image.url }}">
</a>
{% if child.children %}
<ul>
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
I am not getting why it is not working, I don't see any error even I don't see any image url here, my everything is working fine, only going through problem showing menu icon, can anyone help me in this case?

It looks like you're just missing the reference to the object from the page, you're going straight to it's attribute.
I've got a very similar setup with images associated with pages;
class PageImage(PageExtension):
""" Add images to pages """
image = models.FileField(
verbose_name=_("Image"),
upload_to=upload_to('page_images')
)
Which in my templates becomes;
{% if request.current_page.pageimage.image %}
{{ request.current_page.pageimage.image.url }}
{% endif %}
So in your example, if you did this in a template you'd do;
{% if request.current_page.iconextension %}
<img src="{{ request.current_page.iconextension.image.url }}">
{% endif %}
Checking if the extension exists is important to avoid attribute errors etc.
In a menu, the child isn't a Page object though, it's a NavigationNode from the menu system. So it doesn't have your extension.
I think the proper solution to this is to setup a navigation Modifier. The docs for this are here; http://docs.django-cms.org/en/latest/how_to/menus.html#navigation-modifiers
Alternatively you could setup a template tag which you pass your child which could then use the reverse_id attribute to query the database for the Page that corresponds to, and return the iconextension of that page. I've used this method before.

Based on #markwalker_ answer. I did the job successfully in 3 Steps
Step 1 - Add an FontAwesomeField in a page Extension :
https://docs.django-cms.org/en/latest/how_to/extending_page_title.html
For the record here is my code :
In models.py
from django.db import models
# Create your models here.
from cms.extensions import PageExtension
from cms.extensions.extension_pool import extension_pool
class IconExtension(PageExtension):
image = models.ImageField(upload_to='icons', null=True, blank=True)
fontawesomeicon = models.CharField(max_length=100, null=True, blank=True)
extension_pool.register(IconExtension)
In admin.py
from django.contrib import admin
from cms.extensions import PageExtensionAdmin
from .models import IconExtension
class IconExtensionAdmin(PageExtensionAdmin):
pass
admin.site.register(IconExtension, IconExtensionAdmin)
In cms_toolbars.py
from cms.toolbar_pool import toolbar_pool
from cms.extensions.toolbar import ExtensionToolbar
from django.utils.translation import gettext_lazy as _
from .models import IconExtension
#toolbar_pool.register
class IconExtensionToolbar(ExtensionToolbar):
# defines the model for the current toolbar
model = IconExtension
def populate(self):
# setup the extension toolbar with permissions and sanity checks
current_page_menu = self._setup_extension_toolbar()
# if it's all ok
if current_page_menu:
# retrieves the instance of the current extension (if any) and the toolbar item URL
page_extension, url = self.get_page_extension_admin()
if url:
# adds a toolbar item in position 0 (at the top of the menu)
current_page_menu.add_modal_item(_('Page Icon'), url=url,
disabled=not self.toolbar.edit_mode_active, position=0)
Step 2 - Implementing Navigation Modifier
https://docs.django-cms.org/en/latest/how_to/menus.html#navigation-modifiers
In cms_menu.py
from menus.base import Modifier
from menus.menu_pool import menu_pool
from cms.models import Page
class AddIconModifier(Modifier):
"""
This modifier makes the changed_by attribute of a page
accessible for the menu system.
"""
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
if breadcrumb:
return nodes
# Only on last iteration (Voir : https://docs.django-cms.org/en/latest/how_to/menus.html#navigation-modifiers)
if not post_cut:
return nodes
# only consider nodes that refer to cms pages
# and put them in a dict for efficient access
page_nodes = {n.id: n for n in nodes if n.attr["is_page"]}
# retrieve the relevent pages
pages = Page.objects.filter(id__in=page_nodes.keys())
# loop over all relevant pages
for page in pages:
# take the node referring to the page
node = page_nodes[page.id]
if hasattr(page, 'iconextension') and hasattr(page.iconextension ,'fontawesomeicon'):
node.attr["faicon"] = page.iconextension.fontawesomeicon
else:
node.attr["faicon"] = 'fa-arrow-circle-right'
return nodes
menu_pool.register_modifier(AddIconModifier)
Step 3 - Specific navigation template
In my main template :
{% show_menu 0 100 100 100 "partials/navigation.html" %}
In my navigation template (navigation.html)
{% load cms_tags menu_tags cache %}
{% for child in children %}
<li class="nav-item">
<a class="nav-link" href="{{ child.attr.redirect_url|default:child.get_absolute_url }}"><i class="fas fa-fw {{ child.attr.faicon }}"></i>{{ child.get_menu_title }}</a>
{% if child.children %}
<ul class="sub_menu">
{% show_menu from_level to_level extra_inactive extra_active template '' '' child %}
</ul>
{% endif %}
</li>
{% endfor %}

Related

Generating a unique list of Django-Taggit Tags in Wagtail;

I am trying to add a list of category tags in the sidebar of my Wagtail blog index page. The code below does work, but unfortunately it iterates through the posts and lists all the tags as individual tags, which I ultimately end up with duplicate tags. I built my blog from the Wagtail demo and since it doesn't use Views like I am used to, I am not sure where to add .distinct('tags').
Template
{% for b in blogs %}
{% for tag in b.tags.all %}
<li> <i class="glyphicon glyphicon-tag"></i> {{ tag }}<span>{{ tag }}</span>
{% if not forloop.last %} {% endif %}
</li>
{% endfor %}
{% endfor %}
Any logic that would normally go in a view function, can go in the page model's get_context method:
from django.contrib.contenttypes.models import ContentType
from taggit.models import Tag
class BlogIndex(Page):
# ...
def get_context(self, request):
context = super(BlogIndex, self).get_context(request)
blog_content_type = ContentType.objects.get_for_model(BlogPage)
context['tags'] = Tag.objects.filter(
taggit_taggeditem_items__content_type=blog_content_type
)
return context
(the tag-fetching code here is adapted from some internal Wagtail code.)

Custom Page fields in Mezzanine not displaying in template

I am building a CMS in Mezzanine, and all in all I am extremely impressed with the system. I can't tell you how many CMS systems I have attempted to customize in the past and given up in total frustration.
All in all this has been smooth as silk. But I have a custom page for displaying a YouTube video, and the custom field (which is definitely present in the instance, according to the shell) is failing to render in the template.
The app is called mezz_youtube; here is models.py:
from django.db import models
from django.utils.translation import ugettext_lazy as _
from mezzanine.pages.models import Page, RichText
class YouTubePage(Page):
"""
Implements pages with a YouTube video.
"""
video_slug = models.SlugField(u"video ID", max_length=11)
class Meta:
verbose_name = _("YouTube page")
verbose_name_plural = _("YouTube pages")
The Admin works fine and the YouTubePage was created successfully, as the shell shows:
In [1]: from mezz_youtube.models import YouTubePage
In [2]: p = YouTubePage.objects.get()
In [3]: p.pk
Out[3]: 11
In [4]: p.video_slug
Out[4]: u'CKqGbpR4vvM'
But in the template, as shown here with various debugging entries, the custom field does not appear. Here's the template:
{% extends "pages/page.html" %}
{% load mezzanine_tags %}
{% block main %}
<iframe width="853" height="480" src="http://www.youtube.com/embed/{{ page.video_slug }}" frameborder="0" allowfullscreen></iframe>
<p>Video slug is {% if page.video_slug %}present{% else %}absent{% endif %}.</p>
<p>Title: {{ page.title }} </p>
<p>Model: {{ page.content_model }} </p>
<p>fields:</p>
<ul>
{% for field, val in page.fields.iteritems %}
<li>{{ field }}: {{ val }}</li>
{% endfor %}
</ul>
{{ block.super }}
{% endblock %}
Here is the corresponding section of the output:
<iframe width="853" height="480" src="http://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>Video slug is absent.</p>
<p>Title: ladeda </p>
<p>Model: youtubepage </p>
<p>fields:</p>
<ul>
</ul>
As you can see, the title field renders, but the video_slug field does not. Any idea what is going on here?

django-cms "summary view" aggregating content from multiple pages

Django==1.5.1
django-cms==2.4.1
I'd like to make something like a summary view from all the child pages of a selected page in django-cms, pulling out title, truncated content etc with a more... link for each listed child. I've managed to get titles and paths just fine, but im struggling to get content from the placeholders.
I have a templatetag like this:
from cms.models import Page
from cms.utils.page_resolver import get_page_from_path
from django import template
register = template.Library()
#register.inclusion_tag('news_summary_item.html')
def get_news_items():
news_root = get_page_from_path('news')
newsitems = news_root.children.filter(published=True)
return {'newsitems':newsitems}
and here is the template its using:
{% load cms_tags menu_tags %}
<ul>
{% for item in newsitems %}
<li>{{ item.get_title }}
{% for placeholder in item.placeholders.all %}
# {% show_placeholder placeholder.slot item current_language %} #
{% endfor %}
</li>
{% endfor %}
</ul>
Can anyone help with getting the placeholder content here? Ideally, id like to be able to pass it through truncatewords_html to just get a summary, but open to other ways to get the same effect.
Thanks for any tips/pointers!
I had to index CMS content in one project and I get the content of each placeholder, and the content of a placeholder is stored in the plugins attached to it
How te get the content of a CMSPlugin in a view?
from cms.models import CMSPlugin
plugin = CMSPlugin.objects.filter(plugin_type='TextPlugin')[0] # Get first text plugin
# This return the body/content of the plugin:
plugin_content = plugin.get_plugin_instance()[0].body
If you would like to manage other plugins like PicturePlugin you could get the "alt" text like:
plugin_picture_content = plugin.get_plugin_instance()[0].alt
How to get the content of CMSPlugin in a template?
# plugin_object containing a CMSPlugin
{{plugin_object.get_plugin_instance.0.body}}
I supose when you want to get the content, we are talking about TextPlugin, you have to be carefull here because only the plugin type TextPlugin has the attribute body, the PicturePlugin has the attribute alt and the LinkPlugin has the attribute href etc...
Solution adapted for your problem
You are doing a loop over placeholders, so you need to get all the plugins for each placeholder and get the content of each plugin, because the content of the placeholders as I mentioned before are stored in the plugins attached to it (TextPlugin, PicturePlugin, LinkPlugin...).
... ... ...
{% for placeholder in item.placeholders.all %} # Loop over placeholders
{% for plugin in placeholder.get_plugin_list %} # Get plugins for each placeholder
{{plugin.get_plugin_instance.0.body|striptags}}
{% endfor %}
{% endfor %}
... ... ...
And to ensure that you only show the content of TextPlugin and not from other plugins you could do:
... ... ...
{% for placeholder in item.placeholders.all %} # Loop over placeholders
{% for plugin in placeholder.get_plugin_list %} # Get plugins for each placeholder
{% if 'TextPlugin' in plugin.plugin_type %}
{{plugin.get_plugin_instance.0.body|striptags}}
{% endif %}
{% endfor %}
{% endfor %}
... ... ...

How to implement breadcrumbs in a Django template?

Some solutions provided on doing a Google search for "Django breadcrumbs" include using templates and block.super, basically just extending the base blocks and adding the current page to it. http://www.martin-geber.com/thought/2007/10/25/breadcrumbs-django-templates/
http://www.djangosnippets.org/snippets/1289/ - provides a template tag but I'm not sure this would work if you don't have your urls.py properly declared.
I'm wondering what's the best way? And if you have implemented breadcrumbs before how did you do it?
--- Edit --
My question was meant to be: is there a general accepted method of doing breadcrumbs in Django, but from the answers I see there is not, and there are many different solutions, I'm not sure who to award the correct answer to, as I used a variation of using the block.super method, while all the below answers would work.
I guess then this is too much of a subjective question.
Note: I provide the full snippet below, since djangosnippets has been finicky lately.
Cool, someone actually found my snippet :-) The use of my template tag is rather simple.
To answer your question there is no "built-in" django mechanism for dealing with breadcrumbs, but it does provide us with the next best thing: custom template tags.
Imagine you want to have breadcrumbs like so:
Services -> Programming
Services -> Consulting
Then you will probably have a few named urls: "services", and "programming", "consulting":
(r'^services/$',
'core.views.services',
{},
'services'),
(r'^services/programming$',
'core.views.programming',
{},
'programming'),
(r'^services/consulting$',
'core.views.consulting',
{},
'consulting'),
Now inside your html template (lets just look at consulting page) all you have to put is:
//consulting.html
{% load breadcrumbs %}
{% block breadcrumbs %}
{% breadcrumb_url 'Services' services %}
{% breadcrumb_url 'Consulting' consulting %}
{% endblock %}
If you want to use some kind of custom text within the breadcrumb, and don't want to link it, you can use breadcrumb tag instead.
//consulting.html
{% load breadcrumbs %}
{% block breadcrumbs %}
{% breadcrumb_url 'Services' services %}
{% breadcrumb_url 'Consulting' consulting %}
{% breadcrumb 'We are great!' %}
{% endblock %}
There are more involved situations where you might want to include an id of a particular object, which is also easy to do. This is an example that is more realistic:
{% load breadcrumbs %}
{% block breadcrumbs %}
{% breadcrumb_url 'Employees' employee_list %}
{% if employee.id %}
{% breadcrumb_url employee.company.name company_detail employee.company.id %}
{% breadcrumb_url employee.full_name employee_detail employee.id %}
{% breadcrumb 'Edit Employee ' %}
{% else %}
{% breadcrumb 'New Employee' %}
{% endif %}
{% endblock %}
DaGood breadcrumbs snippet
Provides two template tags to use in your HTML templates: breadcrumb and breadcrumb_url. The first allows creating of simple url, with the text portion and url portion. Or only unlinked text (as the last item in breadcrumb trail for example). The second, can actually take the named url with arguments! Additionally it takes a title as the first argument.
This is a templatetag file that should go into your /templatetags directory.
Just change the path of the image in the method create_crumb and you are good to go!
Don't forget to {% load breadcrumbs %} at the top of your html template!
from django import template
from django.template import loader, Node, Variable
from django.utils.encoding import smart_str, smart_unicode
from django.template.defaulttags import url
from django.template import VariableDoesNotExist
register = template.Library()
#register.tag
def breadcrumb(parser, token):
"""
Renders the breadcrumb.
Examples:
{% breadcrumb "Title of breadcrumb" url_var %}
{% breadcrumb context_var url_var %}
{% breadcrumb "Just the title" %}
{% breadcrumb just_context_var %}
Parameters:
-First parameter is the title of the crumb,
-Second (optional) parameter is the url variable to link to, produced by url tag, i.e.:
{% url person_detail object.id as person_url %}
then:
{% breadcrumb person.name person_url %}
#author Andriy Drozdyuk
"""
return BreadcrumbNode(token.split_contents()[1:])
#register.tag
def breadcrumb_url(parser, token):
"""
Same as breadcrumb
but instead of url context variable takes in all the
arguments URL tag takes.
{% breadcrumb "Title of breadcrumb" person_detail person.id %}
{% breadcrumb person.name person_detail person.id %}
"""
bits = token.split_contents()
if len(bits)==2:
return breadcrumb(parser, token)
# Extract our extra title parameter
title = bits.pop(1)
token.contents = ' '.join(bits)
url_node = url(parser, token)
return UrlBreadcrumbNode(title, url_node)
class BreadcrumbNode(Node):
def __init__(self, vars):
"""
First var is title, second var is url context variable
"""
self.vars = map(Variable,vars)
def render(self, context):
title = self.vars[0].var
if title.find("'")==-1 and title.find('"')==-1:
try:
val = self.vars[0]
title = val.resolve(context)
except:
title = ''
else:
title=title.strip("'").strip('"')
title=smart_unicode(title)
url = None
if len(self.vars)>1:
val = self.vars[1]
try:
url = val.resolve(context)
except VariableDoesNotExist:
print 'URL does not exist', val
url = None
return create_crumb(title, url)
class UrlBreadcrumbNode(Node):
def __init__(self, title, url_node):
self.title = Variable(title)
self.url_node = url_node
def render(self, context):
title = self.title.var
if title.find("'")==-1 and title.find('"')==-1:
try:
val = self.title
title = val.resolve(context)
except:
title = ''
else:
title=title.strip("'").strip('"')
title=smart_unicode(title)
url = self.url_node.render(context)
return create_crumb(title, url)
def create_crumb(title, url=None):
"""
Helper function
"""
crumb = """<span class="breadcrumbs-arrow">""" \
"""<img src="/media/images/arrow.gif" alt="Arrow">""" \
"""</span>"""
if url:
crumb = "%s<a href='%s'>%s</a>" % (crumb, url, title)
else:
crumb = "%s %s" % (crumb, title)
return crumb
The Django admin view modules have automatic breadcumbs, which are implemented like this:
{% block breadcrumbs %}
<div class="breadcrumbs">
{% trans 'Home' %}
{% block crumbs %}
{% if title %} › {{ title }}{% endif %}
{% endblock %}
</div>
{% endblock %}
So there is some kind of built-in support for this..
My view functions emit the breadcrumbs as a simple list.
Some information is kept in the user's session. Indirectly, however, it comes from the URL's.
Breadcrumbs are not a simple linear list of where they've been -- that's what browser history is for. A simple list of where they've been doesn't make a good breadcrumb trail because it doesn't reflect any meaning.
For most of our view functions, the navigation is pretty fixed, and based on template/view/URL design. In our cases, there's a lot of drilling into details, and the breadcrumbs reflect that narrowing -- we have a "realm", a "list", a "parent" and a "child". They form a simple hierarchy from general to specific.
In most cases, a well-defined URL can be trivially broken into a nice trail of breadcrumbs. Indeed, that's one test for good URL design -- the URL can be interpreted as breadcrumbs and displayed meaningfully to the users.
For a few view functions, where we present information that's part of a "many-to-many" join, for example, there are two candidate parents. The URL may say one thing, but the session's context stack says another.
For that reason, our view functions have to leave context clues in the session so we can emit breadcrumbs.
Try django-breadcrumbs — a pluggable middleware that add a breadcrumbs callable/iterable in your request object.
It supports simple views, generic views and Django FlatPages app.
I had the same issue and finally I've made simple django tempalate tag for it: https://github.com/prymitive/bootstrap-breadcrumbs
http://www.djangosnippets.org/snippets/1289/ - provides a template tag but i'm not sure this would work if you don't have your urls.py properly declared.
Nothing will work if you don't have your urls.py properly declared. Having said that, it doesn't look as though it imports from urls.py. In fact, it looks like to properly use that tag, you still have to pass the template some variables. Okay, that's not quite true: indirectly through the default url tag, which the breadcrumb tag calls. But as far as I can figure, it doesn't even actually call that tag; all occurrences of url are locally created variables.
But I'm no expert at parsing template tag definitions. So say somewhere else in the code it magically replicates the functionality of the url tag. The usage seems to be that you pass in arguments to a reverse lookup. Again, no matter what your project is, you urls.py should be configured so that any view can be reached with a reverse lookup. This is especially true with breadcrumbs. Think about it:
home > accounts > my account
Should accounts, ever hold an arbitrary, hardcoded url? Could "my account" ever hold an arbitrary, hardcoded url? Some way, somehow you're going to write breadcrumbs in such a way that your urls.py gets reversed. That's really only going to happen in one of two places: in your view, with a call to reverse, or in the template, with a call to a template tag that mimics the functionality of reverse. There may be reasons to prefer the former over the latter (into which the linked snippet locks you), but avoiding a logical configuration of your urls.py file is not one of them.
Try django-mptt.
Utilities for implementing Modified Preorder Tree Traversal (MPTT) with your Django Model classes and working with trees of Model instances.
This answer is just the same as #Andriy Drozdyuk (link). I just want to edit something so it works in Django 3.2 (in my case) and good in bootstrap too.
for create_crumb function (Remove the ">" bug in the current code)
def create_crumb(title, url=None):
"""
Helper function
"""
if url:
crumb = '<li class="breadcrumb-item">{}</li>'.format(url, title)
else:
crumb = '<li class="breadcrumb-item active" aria-current="page">{}</li>'.format(title)
return crumb
And for __init__ in BreadcrumbNode, add list() to make it subscriptable. And change smart_unicode to smart_text in render method
from django.utils.encoding import smart_text
class BreadcrumbNode(Node):
def __init__(self, vars):
"""
First var is title, second var is url context variable
"""
self.vars = list(map(Variable, vars))
def render(self, context):
title = self.vars[0].var
if title.find("'")==-1 and title.find('"')==-1:
try:
val = self.vars[0]
title = val.resolve(context)
except:
title = ''
else:
title=title.strip("'").strip('"')
title=smart_text(title)
And add this in base.html for the view for Bootstrap. Check the docs
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
<ol class="breadcrumb">
{% block breadcrumbs %}
{% endblock breadcrumbs %}
</ol>
</nav>
Obviously, no one best answer, but for practical reason I find that it is worth considering the naïve way. Just overwrite and rewrite the whole breadcrumb... (at least until the official django.contrib.breadcrumb released )
Without being too fancy, it is better to keep things simple. It helps the newcomer to understand. It is extremely customizable (e.g. permission checking, breadcrumb icon, separator characters, active breadcrumb, etc...)
Base Template
<!-- File: base.html -->
<html>
<body>
{% block breadcrumb %}
<ul class="breadcrumb">
<li>Dashboard</li>
</ul>
{% endblock breadcrumb %}
{% block content %}{% endblock content %}
</body>
</html>
Implementation Template
Later on each pages we rewrite and overwrite the whole breadcrumb block.
<!-- File: page.html -->
{% extends 'base.html' %}
{% block breadcrumb %}
<ul class="breadcrumb">
<li>Dashboard</li>
<li>Level 1</li>
<li class="active">Level 2</li>
</ul>
{% endblock breadcrumb %}
Practicallity
Realworld use cases:
Django Oscar: base template, simple bread
Django Admin: base template, simple bread, permission check breadcrumb
You could also reduce the boiler plate required to manage breadcrumbs using django-view-breadcrumbs, by adding a crumbs property to the view.
urls.py
urlpatterns = [
...
path('posts/<slug:slug>', views.PostDetail.as_view(), name='post_detail'),
...
]
views.py
from django.views.generic import DetailView
from view_breadcrumbs import DetailBreadcrumbMixin
class PostDetail(DetailBreadcrumbMixin, DetailView):
model = Post
template_name = 'app/post/detail.html'
base.html
{% load django_bootstrap_breadcrumbs %}
{% block breadcrumbs %}
{% render_breadcrumbs %}
{% endblock %}
Something like this may work for your situation:
Capture the entire URL in your view and make links from it. This will require modifying your urls.py, each view that needs to have breadcrumbs, and your templates.
First you would capture the entire URL in your urls.py file
original urls.py
...
(r'^myapp/$', 'myView'),
(r'^myapp/(?P<pk>.+)/$', 'myOtherView'),
...
new urls.py
...
(r'^(?P<whole_url>myapp/)$', 'myView'),
(r'^(?P<whole_url>myapp/(?P<pk>.+)/)$', 'myOtherView'),
...
Then in your view something like:
views.py
...
def myView(request, whole_url):
# dissect the url
slugs = whole_url.split('/')
# for each 'directory' in the url create a piece of bread
breadcrumbs = []
url = '/'
for slug in slugs:
if slug != '':
url = '%s%s/' % (url, slug)
breadcrumb = { 'slug':slug, 'url':url }
breadcrumbs.append(breadcrumb)
objects = {
'breadcrumbs': breadcrumbs,
}
return render_to_response('myTemplate.html', objects)
...
Which should be pulled out into a function that gets imported into the views that need it
Then in your template print out the breadcrumbs
myTemplate.html
...
<div class="breadcrumb-nav">
<ul>
{% for breadcrumb in breadcrumbs %}
<li>{{ breadcrumb.slug }}</li>
{% endfor %}
</ul>
</div>
...
One shortcoming of doing it this way is that as it stands you can only show the 'directory' part of the url as the link text. One fix for this off the top of my head (probably not a good one) would be to keep a dictionary in the file that defines the breadcrumb function.
Anyways that's one way you could accomplish breadcrumbs, cheers :)
You might want to try django-headcrumbs (don’t worry, they are not going to eat your brains).
It’s very lightweight and absolutely straightforward to use, all you have to do is annotate your views (because defining crumbs structure in templates sounds crazy to me) with a decorator that explains how to get back from the given view.
Here is an example from the documentation:
from headcrumbs.decorators import crumb
from headcrumbs.util import name_from_pk
#crumb('Staff') # This is the root crumb -- it doesn’t have a parent
def index(request):
# In our example you’ll fetch the list of divisions (from a database)
# and output it.
#crumb(name_from_pk(Division), parent=index)
def division(request, slug):
# Here you find all employees from the given division
# and list them.
There are also some utility functions (e.g. name_from_pk you can see in the example) that automagically generate nice names for your crumbs without you having to wright lots of code.
I've created template filter for this.
Apply your custom filter (I've named it 'makebreadcrumbs') to the request.path like this:
{% with request.resolver_match.namespace as name_space %}
{{ request.path|makebreadcrumbs:name_space|safe }}
{% endwith %}
We need to pass url namespace as an arg to our filter.
Also use safe filter, because our filter will be returning string that needs to be resolved as html content.
Custom filter should look like this:
#register.filter
def makebreadcrumbs(value, arg):
my_crumbs = []
crumbs = value.split('/')[1:-1] # slice domain and last empty value
for index, c in enumerate(crumbs):
if c == arg and len(crumbs) != 1:
# check it is a index of the app. example: /users/user/change_password - /users/ is the index.
link = '{}'.format(reverse(c+':index'), c)
else:
if index == len(crumbs)-1:
link = '<span>{}</span>'.format(c)
# the current bread crumb should not be a link.
else:
link = '{}'.format(reverse(arg+':' + c), c)
my_crumbs.append(link)
return ' > '.join(my_crumbs)
# return whole list of crumbs joined by the right arrow special character.
Important:
splited parts of the 'value' in our filter should be equal to the namespace in the urls.py, so the reverse method can be called.
Hope it helped.
A generic way, to collect all callable paths of the current url could be resolved by the following code snippet:
from django.urls import resolve, Resolver404
path_items = request.path.split("/")
path_items.pop(0)
path_tmp = ""
breadcrumb_config = OrderedDict()
for path_item in path_items:
path_tmp += "/" + path_item
try:
resolve(path_tmp)
breadcrumb_config[path_item] = {'is_representative': True, 'current_path': path_tmp}
except Resolver404:
breadcrumb_config[path_item] = {'is_representative': False, 'current_path': path_tmp}
If the resolve function can't get a real path from any urlpattern, the Resolver404 exception will be thrown. For those items we set the is_representative flag to false. The OrderedDict breadcrumb_config holds after that the breadcrumb items with there configuration.
For bootstrap 4 breadcrumb for example, you can do something like the following in your template:
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
{% for crumb, values in BREADCRUMB_CONFIG.items %}
<li class="breadcrumb-item {% if forloop.last or not values.is_representative %}active{% endif %}" {% if forloop.last %}aria-current="page"{% endif %}>
{% if values.is_representative %}
<a href="{{values.current_path}}">
{{crumb}}
</a>
{% else %}
{{crumb}}
{% endif %}
</li>
{% endfor %}
</ol>
</nav>
Only the links which won't raises a 404 are clickable.
I believe there is nothing simpler than that (django 3.2):
def list(request):
return render(request, 'list.html', {
'crumbs' : [
("Today", "https://www.python.org/"),
("Is", "https://www.python.org/"),
("Sunday", "https://www.djangoproject.com/"),
]
})
Breadcrumbs.html
<div class="page-title-right">
<ol class="breadcrumb m-0">
{% if crumbs %}
{% for c in crumbs %}
<li class="breadcrumb-item {{c.2}}">{{c.0}}</li>
{% endfor %}
{% endif %}
</ol>
</div>
css:
.m-0 {
margin: 0!important;
}
.breadcrumb {
display: flex;
flex-wrap: wrap;
padding: 0 0;
margin-bottom: 1rem;
list-style: none;
border-radius: .25rem;
}
dl, ol, ul {
margin-top: 0;
margin-bottom: 1rem;
}
ol, ul {
padding-left: 2rem;
}

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 %}Home{% endblock %}</li>
<li>{% block nav-about %}About{% endblock %}</li>
<li>{% block nav-contact %}Contact{% 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>
I'm the author of django-lineage which I wrote specifically to solve this question :D
I became annoyed using the (perfectly acceptable) jpwatts method in my own projects and drew inspiration from 110j's answer. Lineage looks like this:
{% load lineage %}
<div id="navigation">
<a class="{% ancestor '/home/' %}" href="/home/">Home</a>
<a class="{% ancestor '/services/' %}" href="/services/">Services</a>
<a class="{% ancestor '/contact/' %}" href="/contact/">Contact</a>
</div>
ancestor is simply replaced with "active" if the argument matches the start of current page URL.
Variable arguments, and full {% url %} type reverse resolution, is also supported. I sprinkled in a few configuration options and fleshed it out a little and packaged it up for everyone to use.
If anyone is interested, read a bit more about it at:
>> github.com/marcuswhybrow/django-lineage
Since Django 1.5:
In all generic class-based views (or any class-based view inheriting
from ContextMixin), the context dictionary contains a view variable
that points to the View instance.
So if you are using such views, you could add something likie breadcrumbs as a class level field and use it in your templates.
Example view code:
class YourDetailView(DetailView):
breadcrumbs = ['detail']
(...)
In your template you could use it in this way:
<a href="/detail/" {% if 'detail' in view.breadcrumbs %}class="active"{% endif %}>Detail</a>
If you want to additionally "highlight" parent navigation items, you need to extend breadcrumbs list:
class YourDetailView(DetailView):
breadcrumbs = ['dashboard', 'list', 'detail']
(...)
... and in your template:
<a href="/dashboard/" {% if 'dashboard' in view.breadcrumbs %}class="active"{% endif %}>Dashboard</a>
<a href="/list/" {% if 'list' in view.breadcrumbs %}class="active"{% endif %}>List</a>
<a href="/detail/" {% if 'detail' in view.breadcrumbs %}class="active"{% endif %}>Detail</a>
This is easy and clean solution and works pretty well with nested navigation.
You could apply a class or id to the body element of the page, rather than to a specific nav item.
HTML:
<body class="{{ nav_class }}">
CSS:
body.home #nav_home,
body.about #nav_about { */ Current nav styles */ }
I do it like this:
<a class="tab {% ifequal active_tab "statistics" %}active{% endifequal %}" href="{% url Member.Statistics %}">Statistics</a>
and then all I have to do is in my view add {'active_tab': 'statistics'} to my context dictionary.
If you are using RequestContext you can get current path in your template as:
{{ request.path }}
And in your view:
from django.template import RequestContext
def my_view(request):
# do something awesome here
return template.render(RequestContext(request, context_dict))
I took the code from nivhab above and removed some wierdness and made it into a clean templatetag, modified it so that /account/edit/ will still make /account/ tab active.
#current_nav.py
from django import template
register = template.Library()
#register.tag
def current_nav(parser, token):
import re
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, url):
self.url = url
def render(self, context):
path = context['request'].path
pValue = template.Variable(self.url).resolve(context)
if (pValue == '/' or pValue == '') and not (path == '/' or path == ''):
return ""
if path.startswith(pValue):
return ' class="current"'
return ""
#template.html
{% block nav %}
{% load current_nav %}
{% url home as home_url %}
{% url signup as signup_url %}
{% url auth_login as auth_login_url %}
<ul class="container">
<li>Home</li>
<li>Login</li>
<li>Signup</li>
</ul>
{% endblock %}
This is just a variant of the css solution proposed by Toba above:
Include the following in your base template:
<body id="section-{% block section %}home{% endblock %}">
Then in your templates that extend the base use:
{% block section %}show{% endblock %}
You can then use css to highlight the current area based on the body tag (for example if we have a link with an id of nav-home):
#section-home a#nav-home{
font-weight:bold;
}
You could use the reverse function with the appropriate parameters to get the current url.
Thanks for your answers so far, gents. I've gone for something slightly different again..
In my template:
<li{{ link1_active }}>...link...</li>
<li{{ link2_active }}>...link...</li>
<li{{ link3_active }}>...link...</li>
<li{{ link4_active }}>...link...</li>
Once I've worked out which page I'm on in the logic (usually in urls.py), I pass class="selected" as part of the context under the right name to the template.
Eg if I'm on the link1 page, I'll append {'link1_active':' class="selected"'} to the context for the template to scoop up and inject.
It appears to work and it's fairly clean.
Edit: to keep HTML out of my controller/view, I've modified this a bit:
<li{% if link1_active %} class="selected"{% endif %}>...link...</li>
<li{% if link2_active %} class="selected"{% endif %}>...link...</li>
...
It makes the template a little less readable, but I agree, it's better to not push through raw HTML from the urls file.
I found the best is to use an inclusion tag:
templates/fnf/nav_item.html
<li class="nav-item">
<a class="nav-link {% if is_active %}active{% endif %}" href="{% url url_name %}">{{ link_name }}</a>
</li>
This is just my basic bootstrap nav item I wish to render.
It gets the href value, and optionally the link_name value. is_active is calculated based on the current request.
templatetags/nav.py
from django import template
register = template.Library()
#register.inclusion_tag('fnf/nav_item.html', takes_context=True)
def nav_item(context, url_name, link_name=None):
return {
'url_name': url_name,
'link_name': link_name or url_name.title(),
'is_active': context.request.resolver_match.url_name == url_name,
}
Then use it in a nav:
templates/fnf/nav.html
{% load nav %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<ul class="navbar-nav mr-auto">
{% nav_item 'dashboard' %}
</ul>
I have multiple menus on the same page that are created dynamically through a loop. The posts above relating to the context gave me a quick fix. Hope this helps somebody. (I use this in addition to the active template tag - my fix solves the dynamic issue). It seems like a silly comparison, but it works. I chose to name the variables active_something-unique and something-unique, this way it works with nested menus.
Here is a portion of the view (enough to understand what i am doing):
def project_list(request, catslug):
"render the category detail page"
category = get_object_or_404(Category, slug=catslug, site__id__exact=settings.SITE_ID)
context = {
'active_category':
category,
'category':
category,
'category_list':
Category.objects.filter(site__id__exact=settings.SITE_ID),
}
And this is from the template:
<ul>
{% for category in category_list %}
<li class="tab{% ifequal active_category category %}-active{% endifequal %}">
{{ category.cat }}
</li>
{% endfor %}
</ul>
My solution was to write a simple context processor to set a variable based on the request path:
def navigation(request):
"""
Custom context processor to set the navigation menu pointer.
"""
nav_pointer = ''
if request.path == '/':
nav_pointer = 'main'
elif request.path.startswith('/services/'):
nav_pointer = 'services'
elif request.path.startswith('/other_stuff/'):
nav_pointer = 'other_stuff'
return {'nav_pointer': nav_pointer}
(Don't forget to add your custom processor to TEMPLATE_CONTEXT_PROCESSORS in settings.py.)
Then in the base template I use an ifequal tag per link to determine whether to append the "active" class. Granted this approach is strictly limited to the flexibility of your path structure, but it works for my relatively modest deployment.
I just wanted to share my minor enhancement to nivhab's post. In my application I have subnavigations and I did not want to hide them using just CSS, so I needed some sort of "if" tag to display the subnavigation for an item or not.
from django import template
register = template.Library()
#register.tag
def ifnaviactive(parser, token):
nodelist = parser.parse(('endifnaviactive',))
parser.delete_first_token()
import re
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:], nodelist)
class NavSelectedNode(template.Node):
def __init__(self, patterns, nodelist):
self.patterns = patterns
self.nodelist = nodelist
def render(self, context):
path = context['request'].path
for p in self.patterns:
pValue = template.Variable(p).resolve(context)
if path == pValue:
return self.nodelist.render(context)
return ""
You can use this basically in the same way as the active tag:
{% url product_url as product %}
{% ifnaviactive request product %}
<ul class="subnavi">
<li>Subnavi item for product 1</li>
...
</ul>
{% endifnaviactive %}
Just another ehnancement of the original solution.
This accept multiple patterns and which is best also unnamed patterns written as relative URL wrapped in '"', like following:
{% url admin:clients_client_changelist as clients %}
{% url admin:clients_town_changelist as towns %}
{% url admin:clients_district_changelist as districts %}
<li class="{% active "/" %}">Home</li>
<li class="{% active clients %}">Clients</li>
{% if request.user.is_superuser %}
<li class="{% active towns districts %}">
Settings
<ul>
<li>Towns</li>
<li>Districts</li>
</ul>
</li>
{% endif %}
Tag goes like this:
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, urls):
self.urls = urls
def render(self, context):
path = context['request'].path
for url in self.urls:
if '"' not in url:
cpath = template.Variable(url).resolve(context)
else:
cpath = url.strip('"')
if (cpath == '/' or cpath == '') and not (path == '/' or path == ''):
return ""
if path.startswith(cpath):
return 'active'
return ""
I used jquery to highlight my navbars. This solution simply adds the css class "active" to the item which fits the css selector.
<script type="text/javascript" src="/static/js/jquery.js"></script>
<script>
$(document).ready(function(){
var path = location.pathname;
$('ul.navbar a.nav[href$="' + path + '"]').addClass("active");
});
</script>
A little enhancement over #tback's answer, without any %if% tags:
# navigation.py
from django import template
from django.core.urlresolvers import resolve
register = template.Library()
#register.filter(name="activate_if_active", is_safe=True)
def activate_if_active(request, urlname):
if resolve(request.get_full_path()).url_name == urlname:
return "active"
return ''
Use it in your template like that:
{% load navigation %}
<li class="{{ request|activate_if_active:'url_name' }}">
My View
</li>
And include "django.core.context_processors.request" in your TEMPLATE_CONTEXT_PROCESSORS setting.
Inspired by this solution, I started to use this approach:
**Placed in templates as base.html**
{% block tab_menu %}
<ul class="tab-menu">
<li class="{% if active_tab == 'tab1' %} active{% endif %}">Tab 1</li>
<li class="{% if active_tab == 'tab2' %} active{% endif %}">Tab 2</li>
<li class="{% if active_tab == 'tab3' %} active{% endif %}">Tab 3</li>
</ul>
{% endblock tab_menu %}
**Placed in your page template**
{% extends "base.html" %}
{% block tab_menu %}
{% with active_tab="tab1" %} {{ block.super }} {% endwith %}
{% endblock tab_menu %}
Slightly modifying Andreas' answer, it looks like you can pass in the name of the route from urls.py to the template tag. In my example my_tasks, and then in the template tag function use the reverse function to work out what the URL should be, then you can match that against the URL in the request object (available in the template context)
from django import template
from django.core.urlresolvers import reverse
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, name):
self.name = name
def render(self, context):
if context['request'].path == reverse(self.name[1]):
return 'active'
else:
return ''
urls.py
url(r'^tasks/my', my_tasks, name = 'my_tasks' ),
template.html
<li class="{% active request all_tasks %}">Everyone</li>
I know I'm late to the party. I didn't like any of the popular solutions though:
The block method seems wrong: I think the navigation should be self contained.
The template_tag method seems wrong: I don't like that I have to get the url from the url-tag first. Also, I think the css-class should be defined in the template, not the tag.
I therefore wrote a filter that doesn't have the drawbacks I described above. It returns True if a url is active and can therefore be used with {% if %}:
{% load navigation %}
<li{% if request|active:"home" %} class="active"{% endif %}>Home</li>
The code:
#register.filter(name="active")
def active(request, url_name):
return resolve(request.path_info).url_name == url_name
Just make sure to use RequestContext on pages with navigation or to enable the request context_processor in your settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
...
'django.core.context_processors.request',
)
I've seen jpwatts', 110j's, nivhab's & Marcus Whybrow's answers, but they all seem to lack in something: what about the root path ? Why it's always active ?
So I've made an other way, easier, which make the "controller" decides by itself and I think it resolve most of the big problems.
Here is my custom tag:
## myapp_tags.py
#register.simple_tag
def nav_css_class(page_class):
if not page_class:
return ""
else:
return page_class
Then, the "controller" declares CSS classes needed (in fact, the most important is it declares its presence to the template)
## views.py
def ping(request):
context={}
context["nav_ping"] = "active"
return render(request, 'myapp/ping.html',context)
And finally, I render it in my navigation bar:
<!-- sidebar.html -->
{% load myapp_tags %}
...
<a class="{% nav_css_class nav_home %}" href="{% url 'index' %}">
Accueil
</a>
<a class="{% nav_css_class nav_candidats %}" href="{% url 'candidats' %}">
Candidats
</a>
<a class="{% nav_css_class nav_ping %}" href="{% url 'ping' %}">
Ping
</a>
<a class="{% nav_css_class nav_stat %}" href="{% url 'statistiques' %}">
Statistiques
</a>
...
So each page has its own nav_css_class value to set, and if it's set, the template renders active: no need of request in template context, no URL parcing and no more problems about multi-URL pages or root page.
Here's my go at it. I ended up implementing a class in my views that contains my navigation structure (flat with some metadata). I then inject this to the template and render it out.
My solution deals with i18n. It probably should be abstracted out a bit more but I haven't really bothered with that really.
views.py:
from django.utils.translation import get_language, ugettext as _
class Navi(list):
items = (_('Events'), _('Users'), )
def __init__(self, cur_path):
lang = get_language()
first_part = '/' + cur_path.lstrip('/').split('/')[0]
def set_status(n):
if n['url'] == first_part:
n['status'] == 'active'
for i in self.items:
o = {'name': i, 'url': '/' + slugify(i)}
set_status(o)
self.append(o)
# remember to attach Navi() to your template context!
# ie. 'navi': Navi(request.path)
I defined the template logic using includes like this. Base template:
{% include "includes/navigation.html" with items=navi %}
Actual include (includes/navigation.html):
<ul class="nav">
{% for item in items %}
<li class="{{ item.status }}">
{{ item.name }}
</li>
{% endfor %}
</ul>
Hopefully someone will find this useful! I guess it would be pretty easy to extend that idea to support nested hierarchies etc.
Create an include template "intranet/nav_item.html":
{% load url from future %}
{% url view as view_url %}
<li class="nav-item{% ifequal view_url request.path %} current{% endifequal %}">
{{ title }}
</li>
And include it in the nav element:
<ul>
{% include "intranet/nav_item.html" with view='intranet.views.home' title='Home' %}
{% include "intranet/nav_item.html" with view='crm.views.clients' title='Clients' %}
</ul>
And you need to add this to settings:
from django.conf import global_settings
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.request',
)
here is pretty simple solution, https://github.com/hellysmile/django-activeurl
from this SO Question
{% url 'some_urlpattern_name' as url %}
<a href="{{url}}"{% if request.path == url %} class="active"{% endif %}>Link</a>
Repeat as necessary for each link.
I also used jQuery to highlight it and find it more elegant than cluttering the template with non-semantic Django template tags.
The code below works with nested dropdowns in bootstrap 3 (highlights both the parent, and the child <li> element.
// DOM Ready
$(function() {
// Highlight current page in nav bar
$('.nav, .navbar-nav li').each(function() {
// Count the number of links to the current page in the <li>
var matched_links = $(this).find('a[href]').filter(function() {
return $(this).attr('href') == window.location.pathname;
}).length;
// If there's at least one, mark the <li> as active
if (matched_links)
$(this).addClass('active');
});
});
It's also quite easy to add a click event to return false (or change the href attribute to #) for the current page, without changing the template/html markup:
var matched_links = $(this).find('a[href]').filter(function() {
var matched = $(this).attr('href') == window.location.pathname;
if (matched)
$(this).click(function() { return false; });
return matched;
}).length;
I use a combination of this mixin for class based views:
class SetActiveViewMixin(object):
def get_context_data(self, **kwargs):
context = super(SetActiveViewMixin, self).get_context_data(**kwargs)
context['active_nav_menu'] = {
self.request.resolver_match.view_name: ' class="pure-menu-selected"'
}
return context
with this in the template:
<ul>
<li{{active_nav_menu.node_explorer }}>Explore</li>
<li{{active_nav_menu.node_create }}>Create</li>
<li{{active_nav_menu.node_edit }}>Edit</li>
<li{{active_nav_menu.node_delete }}>Delete</li>
</ul>
Mine is a bit similar to another JS approach submitted previously.. just without jQuery...
Say we have in base.html the following:
<div class="pure-u-1 pure-menu pure-menu-open pure-menu-horizontal header" >
<ul class="">
<li id="home">Home</li>
<li id="news">News</li>
<li id="analysis">Analysis</li>
<li id="opinion">Opinion</li>
<li id="data">Data</li>
<li id="events">Events</li>
<li id="forum">Forum</li>
<li id="subscribe">Subscribe</li>
</ul>
<script type="text/javascript">
(function(){
loc=/\w+/.exec(window.location.pathname)[0];
el=document.getElementById(loc).className='pure-menu-selected';
})();
</script>
</div>
I just made my hierarchy to follow a certain URL pattern... after the host address... i have my main category, eg, home, news, analysis, etc. and the regex just pulls the first word out of the location
**
Just add url and name in jinja format like this
**
<ul class="nav navbar-nav">
<li>
Cities
</li>
<li>
Cafes
</li>
</ul>