Как стать автором
Обновить

Комментарии 11

ИМХО, корректнее реализовывать данную задачу следующим образом:

{% url 'menu_1' as menu_url_1 %}
{% url 'menu_2' as menu_url_2 %}
{% ifequal request.path menu_url_1 %}menu 1 is active{% endifequal %}
{% ifequal request.path menu_url_2 %}menu 2 is active{% endifequal %}

Разумеется не забываем подключить django.core.context_processors.request
На дворе django 1.6, а вы до сих пор пользуетесь ifequal? Серьезно?

Заодно вот такой велосипед:
_urls = (
    (reverse_lazy('app1.index'), u'App 1'),
    (reverse_lazy('app2.index'), u'App 2'),
    (reverse_lazy('app3.index'), u'App 3'),
)

@register.inclusion_tag('menu.html', takes_context=True)
def navigation_menu(context):
    request = context['request']

    urls = []
    full_path = request.get_full_path()
    for href, name in _urls:
        is_current = full_path.startswith(href)
        urls.append([href, name, is_current])

    return {
        'urls': urls,
    }

На дворе django 1.6, а вы до сих пор пользуетесь ifequal? Серьезно?

Я знаю про {% if a == b %}, но вот момент когда ifequal признан устаревшим, честно говоря, я пропустил, тем более что в dev версии доков об этом ни слова (разве что упомянуто об эквивалентности этих записей и всё). Так что дело тут просто в привычке, хотя да, через if запись будет получаться на несколько символов короче.
Я делаю так:
templatetags/navigation.py
import re
from django import template

register = template.Library()

@register.simple_tag
def active(request, pattern):
    if re.search(pattern, request.path):
        return 'active'
    return ''


template.html
{% load navigation %}
... class="first {% active request "^/url1/" %}" ...
... class="{% active request "^/url2/" %}" ...
Хм. Парсить хтмл, регулярками находить нужный пункт навигации ради того чтобы его подсветить… Вам не кажется что это оверкил?! Я правда вот так сразу не предложу простого и универсального решения. Ваш вариант я пожалуй применял бы только в случае когда менюшки автоматически генерируются.

Когдато давно в своем проектике я решил эту проблему на уровне наследования в шаблонах. В главном шаблоне
...
<li class="{%block about%}{%endblock%}"><a href="/">О проекте</a></li>
<li class="{%block search%}{%endblock%}"><a href="/search">Поиск</a></li>
<li class="{%block contacts%}{%endblock%}"><a href="/contact">Обратная связь</a></li>
...

а в шаблонах отдельных страниц просто доблял
{%block contacts%} active{%endblock%}

Тупое решение в лоб, но для небольшого проекта в самый раз. Сейчас я бы поискал более изящное решение.
Ну не всем же нужно древовидное меню и django-mptt:

Requirements

django-mptt >= 0.5.2
Более сложный вариант. Пользуюсь им уже года два

import re
from django import template
register = template.Library()

@register.simple_tag
def active_tag(request, patterns, out='selected'):
    """
    usage:
        <a class="url{% active_tag request "default /home/" %}" href="#">url item 1</a>
        -> <a class="url seleced">url item 1</a>

        <a class="url{% active_tag request "/posts/ /allposts/" "custom-css" %}" href="#">url item 2</a>
        -> <a class="url custom-css">url item 2</a>
        
        {% active_tag request '^/account/-/(\w+)/$ ^/account/-/(\w+)/edit/$ ^/account/-/(\w+)/password/$' 'class="selected"'%}
        
        {% active_tag request obj.get_absolute_url %}
    """
    if "default" in patterns.split() and request.path == '/':
        return " %s" % out
    else:
        return " %s" % out if len([p for p in patterns.split() 
                            if re.search(p, request.path) ]) else ''
0) таки тянет на оверкилл
1) а как поступать со вложенной навигацией и вообще случаями менее очевидными, чем request.url === page.url?
2) свой велосипед — хорошо, но не стоило бы начать с обзора существующих? в том числе и эту статью…
А почему все так любят привязываться к конкретному URL, типа {% active request "^/url1/" %}, забывая про reverse()? Хардкодинг URL — зло.

Вот и мой двухколёсный друг:
@register.filter
def is_current_page(request, param):
    params = param.split(',')
    name = params[0]
    args, kwargs, as_var = parse_args_and_kwargs(params[1:])
    # Do not mix args and kwargs in reverse() - it is forbidden!
    if args:
        return request.path == reverse(name, args=args)
    elif kwargs:
        return request.path == reverse(name, kwargs=kwargs)
    else:
        return request.path == reverse(name)


В шаблоне:
{% if request|is_current_page:'shop/product,id=1' %} active {% endif %}


Как уже говорили выше, парсить собственноручно написанный шаблон (не какой-то там чужой сайт!) — это точно оверкилл. Напишите шаблон так, чтоб не парсить.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации