Навигация в django

Я только что сделал свой первый маленький webapp в джанго, и мне это нравится. Я собираюсь начать преобразовывать старый PHP-сайт в django и как часть его шаблона, есть панель навигации.

В PHP я проверяю каждый URL-адрес параметра навигации по текущему URL-адресу, в коде шаблона и применяю класс CSS, если они выстраиваются в линию. Это ужасно грязно.

Есть ли что-то лучше для django или хороший способ обработки кода в шаблоне?

Чтобы начать, как мне получить текущий URL?

Ответ 1

Я использую наследование шаблонов для настройки навигации. Например:

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 %}

Ответ 2

Вам не нужно, если это сделать, посмотрите на следующий код:

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>

что он. для деталей реализации смотрите:
gnuvince.wordpress.com
110j.wordpress.com

Ответ 3

Мне понравилась чистота выше 110j, поэтому я взял большую ее часть и провел рефакторинг, чтобы решить 3 проблемы, которые у меня были:

  1. регулярное выражение сопоставляло домашний URL со всеми остальными
  2. Мне нужно было несколько URL, привязанных к одной вкладке навигации, поэтому мне нужен был более сложный тег, который принимает переменное количество параметров
  3. исправлены некоторые проблемы с URL

Вот:

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>

Ответ 4

Я автор django-lineage, который я написал специально для решения этого вопроса: D

Меня раздражало использование (совершенно приемлемого) метода jpwatts в моих собственных проектах и ​​черпало вдохновение из ответа 110j. Lineage выглядит следующим образом:

{% 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 просто заменяется на "активным", если аргумент соответствует началу текущего URL-адреса страницы.

Также поддерживаются переменные аргументы и полное обратное разрешение типа {% url %}. Я посыпал несколькими вариантами конфигурации и немного скрепил его и упаковал для всех, чтобы использовать.

Если кому-то интересно, прочитайте немного об этом по адресу:

github.com/marcuswhybrow/django-lineage

Ответ 5

Так как Django 1.5:

Во всех общих представлениях на основе классов (или любом наследовании на основе класса из ContextMixin), словарь контекста содержит переменную вида который указывает на экземпляр View.

Итак, если вы используете такие представления, вы можете добавить что-то likie breadcrumbs в качестве поля уровня класса и использовать его в своих шаблонах.

Пример кода вида:

class YourDetailView(DetailView):
     breadcrumbs = ['detail']
     (...)

В шаблоне вы можете использовать его следующим образом:

<a href="/detail/" {% if 'detail' in view.breadcrumbs %}class="active"{% endif %}>Detail</a>

Если вы хотите дополнительно выделить элементы родительской навигации, вам нужно расширить список breadcrumbs:

class YourDetailView(DetailView):
     breadcrumbs = ['dashboard', 'list', 'detail']
     (...)

... и в вашем шаблоне:

<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>

Это простое и чистое решение и прекрасно работает с вложенной навигацией.

Ответ 6

Вы можете применить класс или идентификатор к элементу тела страницы, а не к определенному элементу навигации.

HTML:

<body class="{{ nav_class }}">

CSS

body.home #nav_home,
body.about #nav_about { */ Current nav styles */ }

Ответ 7

Я делаю это так:

<a class="tab {% ifequal active_tab "statistics" %}active{% endifequal %}" href="{% url Member.Statistics %}">Statistics</a>

а затем все, что мне нужно сделать, это, на мой взгляд, добавить {'active_tab': 'statistics'} в мой контекстный словарь.

Если вы используете RequestContext, вы можете получить текущий путь в своем шаблоне как:

{{ request.path }}

И на ваш взгляд:

from django.template import RequestContext

def my_view(request):
    # do something awesome here
    return template.render(RequestContext(request, context_dict))

Ответ 8

Я взял код из nivhab выше и удалил некоторую wierdness и превратил его в чистый templatetag, изменил его, чтобы/account/edit/все равно активировал /account/tab.

#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><a href="{{ home_url }}"{% current_nav home_url %} title="Home">Home</a></li>
    <li><a href="{{ auth_login_url }}"{% current_nav auth_login_url %} title="Login">Login</a></li>
    <li><a href="{{ signup_url }}"{% current_nav signup_url %} title="Signup">Signup</a></li>
</ul>
{% endblock %}

Ответ 9

Это всего лишь вариант решения css, предложенного Тоба выше:

Включите в базовый шаблон следующее:

<body id="section-{% block section %}home{% endblock %}">

Затем в ваших шаблонах, которые расширяют базу, используйте:

{% block section %}show{% endblock %}

Затем вы можете использовать css для выделения текущей области на основе тега body (например, если у нас есть ссылка с идентификатором nav-home):

#section-home a#nav-home{
 font-weight:bold;
}

Ответ 10

Вы можете использовать обратную функцию с соответствующими параметрами для получения текущего URL-адреса.

Ответ 11

Спасибо за ваши ответы до сих пор, джентльмены. Я снова пошел за чем-то другим.

В моем шаблоне:

<li{{ link1_active }}>...link...</li>
<li{{ link2_active }}>...link...</li>
<li{{ link3_active }}>...link...</li>
<li{{ link4_active }}>...link...</li>

Как только я выяснил, на какой странице я в логике (обычно в urls.py), я передаю class="selected" как часть контекста под правильным именем в шаблон.

Например, если я на странице link1, я добавлю {'link1_active':' class="selected"'} в контекст для шаблона, чтобы зачерпнуть и вставить.

Кажется, что он работает, и он довольно чистый.

Изменить: чтобы оставить HTML из моего контроллера/представления, я немного изменил это:

<li{% if link1_active %} class="selected"{% endif %}>...link...</li>
<li{% if link2_active %} class="selected"{% endif %}>...link...</li>
...

Это делает шаблон немного менее удобочитаемым, но я согласен, лучше не проталкивать необработанный HTML из файла urls.

Ответ 12

У меня есть несколько меню на той же странице, которые динамически создаются с помощью цикла. Посты выше, относящиеся к контексту, дали мне быстрое решение. Надеюсь, это поможет кому-то. (Я использую это в дополнение к активному тегу шаблона - мое исправление решает динамическую проблему). Это похоже на глупое сравнение, но оно работает. Я решил назвать переменные active_something-unique и что-то уникальным, поэтому он работает с вложенными меню.

Вот часть представления (достаточно, чтобы понять, что я делаю):

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),

    }

И это из шаблона:

<ul>
  {% for category in category_list %}
    <li class="tab{% ifequal active_category category %}-active{% endifequal %}">
      <a href="{{ category.get_absolute_url }}">{{ category.cat }}</a>
    </li>
  {% endfor %}
</ul>

Ответ 13

Мое решение состояло в том, чтобы написать простой процессор контекста для установки переменной на основе пути запроса:

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}

(Не забудьте добавить свой настраиваемый процессор в TEMPLATE_CONTEXT_PROCESSORS в settings.py.)

Затем в базовом шаблоне я использую тег ifequal для каждой ссылки, чтобы определить, добавлять ли "активный" класс. Данный подход строго ограничивается гибкостью структуры вашего пути, но он работает для моего относительно скромного развертывания.

Ответ 14

Я просто хотел поделиться своим незначительным улучшением с сообщением nivhab. В моем приложении у меня есть субнавигации, и я не хотел скрывать их, используя только CSS, поэтому мне понадобился какой-то тэг "if", чтобы отображать субнавигация для элемента или нет.

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 ""

Вы можете использовать это в основном так же, как активный тег:

{% url product_url as product %}

{% ifnaviactive request product %}
    <ul class="subnavi">
        <li>Subnavi item for product 1</li>
        ...
    </ul>
{% endifnaviactive %}

Ответ 15

Просто еще одно исходное решение.

Это принимает несколько шаблонов и которые лучше всего также неназванные шаблоны, написанные как относительный URL, завернутый в '' ', например:

{% url admin:clients_client_changelist as clients %}
{% url admin:clients_town_changelist as towns %}
{% url admin:clients_district_changelist as districts %}

<li class="{% active "/" %}"><a href="/">Home</a></li>
<li class="{% active clients %}"><a href="{{ clients }}">Clients</a></li>
{% if request.user.is_superuser %}
<li class="{% active towns districts %}">
    <a href="#">Settings</a>
    <ul>
        <li><a href="{{ towns }}">Towns</a></li>
        <li><a href="{{ districts }}">Districts</a></li>
    </ul>
</li>
{% endif %}

Тег выглядит следующим образом:

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 ""

Ответ 16

Я использовал jquery, чтобы выделить мои навигаторы. Это решение просто добавляет класс css "active" к элементу, который подходит для селектора css.

<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>

Ответ 17

Небольшое повышение по сравнению с @tback ответом без тегов %if%:

# 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 ''

Используйте его в своем шаблоне следующим образом:

{% load navigation %}
<li class="{{ request|activate_if_active:'url_name' }}">
  <a href="{% url 'url_name' %}">My View</a>
</li>

И включите "django.core.context_processors.request" в настройку TEMPLATE_CONTEXT_PROCESSORS.

Ответ 18

Немного изменив ответ Андреаса, похоже, что вы можете передать имя маршрута от urls.py до тега шаблона. В моем примере my_tasks, а затем в функции тега шаблона используйте обратную функцию для определения того, каким должен быть URL-адрес, тогда вы можете сопоставить это с URL-адресом в объекте запроса (доступным в контексте шаблона)

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 %}"><a href="{% url all_tasks %}">Everyone</a></li>

Ответ 19

Я знаю, что опаздываю на вечеринку. Мне не понравилось ни одно из популярных решений:

метод блока кажется неправильным: я думаю, что навигация должна быть автономной.

Метод template_tag кажется неправильным: мне не нравится, что мне нужно сначала получить URL-адрес из url-тега. Кроме того, я думаю, что css-класс должен быть определен в шаблоне, а не в теге.

Поэтому я написал фильтр, который не имеет недостатков, описанных выше. Он возвращает True, если URL-адрес активен и поэтому может использоваться с {% if %}:

{% load navigation %}
<li{% if request|active:"home" %} class="active"{% endif %}><a href="{% url "home" %}">Home</a></li>

Код:

@register.filter(name="active")
def active(request, url_name):
    return resolve(request.path_info).url_name == url_name

Просто используйте RequestContext на страницах с навигацией или включите запрос context_processor в settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    'django.core.context_processors.request',
)

Ответ 20

Я видел jpwatts ', 110j, nivhab & Marcus Whybrow отвечает, но им все, кажется, не хватает чего-то: как насчет корневого пути? Почему он всегда активен?

Итак, я сделал другой способ, проще, что делает "контроллер" решает сам по себе, и я думаю, что он разрешает большинство больших проблем.

Вот мой пользовательский тег:

## myapp_tags.py

@register.simple_tag
def nav_css_class(page_class):
    if not page_class:
        return ""
    else:
        return page_class

Затем "контроллер" объявляет необходимые классы CSS (на самом деле, самое главное, он объявляет о своем присутствии шаблону)

## views.py

def ping(request):
    context={}
    context["nav_ping"] = "active"
    return render(request, 'myapp/ping.html',context)

И, наконец, я делаю это в своей панели навигации:

<!-- 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>
...

Таким образом, каждая страница имеет собственное значение nav_css_class для установки, и если оно установлено, шаблон отображает активный: нет необходимости в request в контексте шаблона, без парсинга URL и больше проблем с страницами с несколькими URL-адресами или с корневым стр.

Ответ 21

Вот иди сюда. Я закончил реализацию класса в своих представлениях, в котором содержится моя структура навигации (квартира с некоторыми метаданными). Затем я вставляю это в шаблон и вынимаю его.

Мое решение имеет дело с i18n. Вероятно, это должно быть абстрагировано немного больше, но на самом деле я действительно не беспокоился об этом.

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)

Я определил логику шаблона, используя include this this. Базовый шаблон:

{% include "includes/navigation.html" with items=navi %}

Фактическое включает (включает/navigation.html):

 <ul class="nav">
     {% for item in items %}
         <li class="{{ item.status }}">
             <a href="{{ item.url }}">{{ item.name }}</a>
         </li>
     {% endfor %}
 </ul>

Надеюсь, кто-то найдет это полезным! Я думаю, было бы довольно легко расширить эту идею, чтобы поддерживать вложенные иерархии и т.д.

Ответ 22

Создайте шаблон включения "intranet/nav_item.html":

{% load url from future %}

{% url view as view_url %}
<li class="nav-item{% ifequal view_url request.path %} current{% endifequal %}">
    <a href="{{ view_url }}">{{ title }}</a>
</li>

И включите его в элемент nav:

<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>

И вам нужно добавить это в настройки:

from django.conf import global_settings
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
    'django.core.context_processors.request',
)

Ответ 24

из этого SO Вопрос

{% url 'some_urlpattern_name' as url %}
<a href="{{url}}"{% if request.path == url %} class="active"{% endif %}>Link</a>

Повторите, если необходимо, для каждой ссылки.

Ответ 25

Я также использовал jQuery, чтобы выделить его и найти его более элегантным, чем загромождение шаблона с не семантическими тегами шаблона Django.

Нижеприведенный код работает с вложенными выпадающими списками в bootstrap 3 (выделяет как родительский, так и дочерний элемент <li>.

// 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 at least one, mark the <li> as active
        if (matched_links)
            $(this).addClass('active');
    });
});

Также довольно легко добавить событие click в return false (или изменить атрибут href на #) для текущей страницы без изменения разметки шаблона /html:

        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;

Ответ 26

Я использую комбинацию этого mixin для представлений на основе классов:

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

с этим в шаблоне:

<ul>
    <li{{active_nav_menu.node_explorer }}><a href="{% url 'node_explorer' '' %}">Explore</a></li>
    <li{{active_nav_menu.node_create }}><a href="{% url 'node_create' path %}">Create</a></li>
    <li{{active_nav_menu.node_edit }}><a href="{% url 'node_edit' path %}">Edit</a></li>
    <li{{active_nav_menu.node_delete }}><a href="{% url 'node_delete' path %}">Delete</a></li>
</ul>

Ответ 27

Мина немного похожа на другой подход JS, представленный ранее.. просто без jQuery...

Скажем, у нас в base.html следующее:

<div class="pure-u-1 pure-menu pure-menu-open pure-menu-horizontal header" >
    <ul class="">
        <li id="home"><a href="{% url 'article:index' %}">Home</a></li>
        <li id="news"><a href="{% url 'article:index' %}">News</a></li>
        <li id="analysis"><a href="{% url 'article:index' %}">Analysis</a></li>
        <li id="opinion"><a href="{% url 'article:index' %}">Opinion</a></li>
        <li id="data"><a href="{% url 'article:index' %}">Data</a></li>
        <li id="events"><a href="{% url 'article:index' %}">Events</a></li>
        <li id="forum"><a href="{% url 'article:index' %}">Forum</a></li>
        <li id="subscribe"><a href="{% url 'article:index' %}">Subscribe</a></li>
    </ul>
    <script type="text/javascript">
        (function(){
            loc=/\w+/.exec(window.location.pathname)[0];
            el=document.getElementById(loc).className='pure-menu-selected';         
        })();   
    </script>
</div>

Я только что сделал свою иерархию для отслеживания определенного шаблона URL... после адреса хоста... У меня есть моя основная категория, например, домашняя страница, новости, анализ и т.д., и регулярное выражение просто вытаскивает первое слово из расположение

Ответ 28

Вдохновленный этим решением, я начал использовать этот подход:

**Placed in templates as base.html**

{% block tab_menu %}
<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>
{% endblock tab_menu %}

**Placed in your page template**

{% extends "base.html" %}

{% block tab_menu %}
  {% with active_tab="tab1" %} {{ block.super }} {% endwith %}
{% endblock tab_menu %}