34
I found easy and elegant DRY solution.
Itโs the snippet:
http://djangosnippets.org/snippets/2421/
**Placed in templates/includes/tabs.html**
<ul class="tab-menu">
<li class="{% if active_tab == 'tab1' %} active{% endif %}"><a href="#">Tab 1</a></li>
<li class="{% if active_tab == 'tab2' %} active{% endif %}"><a href="#">Tab 2</a></li>
<li class="{% if active_tab == 'tab3' %} active{% endif %}"><a href="#">Tab 3</a></li>
</ul>
**Placed in your page template**
{% include "includes/tabs.html" with active_tab='tab1' %}
105
Figured out another way to do it, elegant enough thanks to this answer : https://stackoverflow.com/a/17614086/34871
Given an url pattern such as:
url(r'^some-url', "myapp.myview", name='my_view_name'),
my_view_name
is available to the template through request
( remember you need to use a RequestContext โ which is implicit when using render_to_response )
Then menu items may look like :
<li class="{% if request.resolver_match.url_name == "my_view_name" %}active{% endif %}"><a href="{% url "my_view_name" %}">Shortcut1</a></li>
<li class="{% if request.resolver_match.url_name == "my_view_name2" %}active{% endif %}"><a href="{% url "my_view_name2" %}">Shortcut2</a></li>
etc.
This way, the url can change and it still works if url parameters vary, and you donโt need to keep a list of menu items elsewhere.
- [Django]-Aggregate (and other annotated) fields in Django Rest Framework serializers
- [Django]-Override existing Django Template Tags
- [Django]-How to reload modules in django shell?
58
Using template tag
You can simply use the following template tag:
# path/to/templatetags/mytags.py
import re
from django import template
try:
from django.urls import reverse, NoReverseMatch
except ImportError:
from django.core.urlresolvers import reverse, NoReverseMatch
register = template.Library()
@register.simple_tag(takes_context=True)
def active(context, pattern_or_urlname):
try:
pattern = '^' + reverse(pattern_or_urlname)
except NoReverseMatch:
pattern = pattern_or_urlname
path = context['request'].path
if re.search(pattern, path):
return 'active'
return ''
So, in you your template:
{% load mytags %}
<nav><ul>
<li class="nav-home {% active 'url-name' %}"><a href="#">Home</a></li>
<li class="nav-blog {% active '^/regex/' %}"><a href="#">Blog</a></li>
</ul></nav>
Using only HTML & CSS
There is another approach, using only HTML & CSS, that you can use in any framework or static sites.
Considering you have a navigation menu like this one:
<nav><ul>
<li class="nav-home"><a href="#">Home</a></li>
<li class="nav-blog"><a href="#">Blog</a></li>
<li class="nav-contact"><a href="#">Contact</a></li>
</ul></nav>
Create some base templates, one for each session of your site, as for example:
home.html
base_blog.html
base_contact.html
All these templates extending base.html
with a block โsectionโ, as for example:
...
<body id="{% block section %}section-generic{% endblock %}">
...
Then, taking the base_blog.html
as example, you must have the following:
{% extends "base.html" %}
{% block section %}section-blog{% endblock %}
Now it is easy to define the actived menu item using CSS only:
#section-home .nav-home,
#section-blog .nav-blog,
#section-contact .nav-contact { background-color: #ccc; }
- [Django]-Creating Custom Filters for list_filter in Django Admin
- [Django]-Django โ Static file not found
- [Django]-Table thumbnail_kvstore doesn't exist
4
You could make a context variable links
with the name, URL and whether itโs an active item:
{% for name, url, active in links %}
{% if active %}
<span class='active'>{{ name }}</span>
{% else %}
<a href='{{ url }}'>{{ name }}</a>
{% endif %}
{% endfor %}
If this menu is present on all pages, you could use a context processor:
def menu_links(request):
links = []
# write code here to construct links
return { 'links': links }
Then, in your settings file, add that function to TEMPLATE_CONTEXT_PROCESSORS
as follows: path.to.where.that.function.is.located.menu_links
. This means the function menu_links
will be called for every template and that means the variable links
is available in each template.
- [Django]-Threaded Django task doesn't automatically handle transactions or db connections?
- [Django]-How to stream an HttpResponse with Django
- [Django]-Django Rest framework, how to include '__all__' fields and a related field in ModelSerializer ?
4
I have come up with a way to utilize block tags within menu-containing parent template to achieve something like this.
base.html
โ the parent template:
<a href="/" class="{% block menu_home_class %}{% endblock %}">Home</a>
<a href="/about" class="{% block menu_about_class %}{% endblock %}">About</a>
<a href="/contact" class="{% block menu_contact_class %}{% endblock %}">Contact</a>
{% block content %}{% endblock %}
about.html
โ template for a specific page:
{% extends "base.html" %}
{% block menu_about_class %}active{% endblock %}
{% block content %}
About page content...
{% endblock %}
As you can see, the thing that varies between different page templates is the name of the block containing active
. contact.html
would make use of menu_contact_class
, and so on.
One benefit of this approach is that you can have multiple subpages with the same active menu item. For example, an about page might have subpages giving information about each team members of a company. It could make sense to have the About menu item stay active for each of these subpages.
- [Django]-How can I disable logging while running unit tests in Python Django?
- [Django]-How to create an object for a Django model with a many to many field?
- [Django]-Direct assignment to the forward side of a many-to-many set is prohibited. Use emails_for_help.set() instead
3
Here ist my solution:
{% url 'module:list' as list_url %}
{% url 'module:create' as create_url %}
<ul>
<li><a href="{% url 'module:list' %}" class="{% if request.path == list_url %}active{% endif %}">List Page</a></li>
<li><a href="{% url 'module:create' %}" class="{% if request.path == create_url %}active{% endif %}">Creation Page</a></li>
</ul>
- [Django]-Gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3> django
- [Django]-Create Django model or update if exists
- [Django]-What is the easiest way to clear a database from the CLI with manage.py in Django?
1
Assuming the nav item is a link with the same URL as the current page, you could just use JavaScript. Hereโs an annotated method that I use to add a class="active"
to a li
in a navigation menu with class="nav"
:
// Get the path name (the part directly after the URL) and append a trailing slash
// For example, 'http://www.example.com/subpage1/sub-subpage/'
// would become '/subpage1/'
var pathName = '/' + window.location.pathname.split('/')[1];
if ( pathName != '/' ) { pathName = pathName + '/'; }
// Form the rest of the URL, so that we now have 'http://www.example.com/subpage1/'
// This returns a top-level nav item
var url = window.location.protocol + '//' +
window.location.host +
pathName;
console.log(url);
// Add an 'active' class to the navigation list item that contains this url
var $links = document.querySelectorAll('.nav a');
$link = Array.prototype.filter.call( $links, function(el) {
return el.href === url;
})[0];
$link.parentNode.className += ' active';
This method means you can simply pop it into your base template once and forget about it. No repetition, and no manual specification of the page URL in each template.
One caveat: this obviously only works if the url
found matches a navigation link href
. It would additionally be possible to specify a couple of special use cases in the JS, or target a different parent element as needed.
Hereโs a runnable example (keep in mind, snippets run on StackSnippets):
// Get the path name (the part directly after the URL) and append a trailing slash
// For example, 'http://www.example.com/subpage1/sub-subpage/'
// would become '/subpage1/'
var pathName = '/' + window.location.pathname.split('/')[1];
if ( pathName != '/' ) { pathName = pathName + '/'; }
// Form the rest of the URL, so that we now have 'http://www.example.com/subpage1/'
// This returns a top-level nav item
var url = window.location.protocol + '//' +
window.location.host +
pathName;
console.log(url);
// Add an 'active' class to the navigation list item that contains this url
var $links = document.querySelectorAll('.nav a');
$link = Array.prototype.filter.call( $links, function(el) {
return el.href === url;
})[0];
$link.parentNode.className += ' active';
li {
display: inline-block;
margin: 0 10px;
}
a {
color: black;
text-decoration: none;
}
.active a {
color: red;
}
<ul class="nav">
<li>
<a href="http://example.com/">Example Link</a>
</li>
<li>
<a href="http://stacksnippets.net/js/">This Snippet</a>
</li>
<li>
<a href="https://google.com/">Google</a>
</li>
<li>
<a href="http://stackoverflow.com/">StackOverflow</a>
</li>
</ul>
- [Django]-How can I temporarily disable a foreign key constraint in MySQL?
- [Django]-Django REST framework: non-model serializer
- [Django]-How to automatically login a user after registration in django
1
I ran into this challenge today with how to dynamically activate a โcategoryโ in a sidebar. The categories have slugs which are from the DB.
I solved it by checking to see category slug was in the current path. The slugs are unique (standard practice) so I think this should work without any conflicts.
{% if category.slug in request.path %}active{% endif %}
Full example code of the loop to get the categories and activate the current one.
{% for category in categories %}
<a class="list-group-item {% if category.slug in request.path %}active{% endif %}" href="{% url 'help:category_index' category.slug %}">
<span class="badge">{{ category.article_set.count }}</span>
{{ category.title }}
</a>
{% endfor %}
- [Django]-Django "You have unapplied migrations". Which ones?
- [Django]-How do I use pagination with Django class based generic ListViews?
- [Django]-Get virtualenv's bin folder path from script
0
Based on @vincentโs answer, there is an easier way to do this without messing up with django url patterns.
The current request path can be checked against the rendered menu item path, and if they match then this is the active item.
In the following example I use django-mptt to render the menu but one can replace node.path
with each menu item path.
<li class="{% if node.path == request.path %}active{% endif %}">
<a href="node.path">node.title</a>
</li>
- [Django]-What is the easiest way to clear a database from the CLI with manage.py in Django?
- [Django]-Django model constraint for related objects
- [Django]-How to disable admin-style browsable interface of django-rest-framework?
0
I am using an easier and pure CSS solution. It has its limitations, of which I know and can live with, but it avoids clumsy CSS class selectors, like this:
<a href="index.html" class="item{% if url == request.path %}active{% endif %}">index</a>
Because a space character before active
is missing the class selector gets called itemactive
instead of item active
and this isnโt exactly too difficult to get wrong like that.
For me this pure CSS solution works much better:
a.item /* all menu items are of this class */
{
color: black;
text-decoration: none;
}
a.item[href~="{{ request.path }}"] /* just the one which is selected matches */
{
color: red;
text-decoration: underline;
}
Notice: This even works if the URL has additional path components, because then href
also matches partially. That could eventually cause โcollisionsโ with more than one match, but often enough it just works, because on well structured websites a โsubdirectoryโ of an URL usually is a child of the selected menu item.
- [Django]-How to simplify migrations in Django 1.7?
- [Django]-How to do SELECT COUNT(*) GROUP BY and ORDER BY in Django?
- [Django]-Get the latest record with filter in Django
0
I personally find the simplest way is to create blocks for each link like so:
# base.py
...
<a href="{% url 'home:index' %}" class={% block tab1_active %}{% endblock %}>
...
<a href="{% url 'home:form' %}" class={% block tab2_active %}{% endblock %}>
...
And then in each relative template declare that link as "active" e.g.:
tab1 template:
{% block tab1_active %}"active"{% endblock %}
tab2 template:
{% block tab2_active %}"active"{% endblock %}
- [Django]-Execute code when Django starts ONCE only?
- [Django]-Equivalent of PHP "echo something; exit();" with Python/Django?
- [Django]-How to display the current year in a Django template?
0
Simply use template tags
# app/templatetags/cores.py
from django import template
from django.shortcuts import reverse
register = template.Library()
@register.simple_tag
def active(request, url, classname):
if request.path == reverse(url):
return classname
return ""
Do like this in your template
{% load cores %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example</title>
</head>
<body>
<div>
<a href="{% url 'myUrl' %}" class="{% active request 'myUrl' 'activeClass' %}">myUrl</a>
</div>
</body>
</html>
Have fun
- [Django]-No Module named django.core
- [Django]-'EntryPoints' object has no attribute 'get' โ Digital ocean
- [Django]-Django โ Annotate multiple fields from a Subquery