Django - выделить навигацию на основе текущей страницы?

Я строю веб-приложение, которое имеет несколько основных разделов. Каждый раздел имеет несколько подразделов. у меня есть main_nav.html файл, который содержит навигацию для основного раздела. Это добавлено к основанным HTML файл с {% include ... %} команда в base.html шаблон. Кроме того, у меня есть несколько навигационных файлов подразделов, каждый из которых добавляется на любую страницу с одинаковыми {% include ... %} команда.

Все навигационные панели очень простые, просто текст с <a href...> теги.

Я хочу выделить ссылку на текущий основной раздел и текущий подраздел. Поскольку это веб-приложение довольно большое, я надеялся как-то сделать это, не добавляя информацию, относящуюся к конкретной странице. Кроме того, я хочу, чтобы он просто "работал", поскольку веб-приложение расширяется и включает больше разделов и подразделов. Например, можно ли это сделать, посмотрев на действующий URL-адрес? Я надеялся поместить это в сами файлы nav и не загружать какую-либо переменную или что-либо еще в каждом представлении django.

Так, например, навигация выглядит так:

(main ->)            [Systems][Invoices][Work Orders][Admin]
(system sub-nav ->)  [Owner][Billing][Contacts]

Так что если я в Billing раздел SystemsХочу ссылку Systems жирным шрифтом и ссылка Billing быть смелым (или какой-то другой простой момент)

Или же:

(main ->)                 [Systems][Invoices][Work Orders][Admin]
(Work-Orders sub-nav ->)  [Create New][Outstanding]

Если я в Outstanding раздел Work Orders, ссылка Work Orders и ссылка Outstanding должен быть выделен.

Есть идеи?

8 ответов

Решение

Предполагая, что вы используете render_to_response с RequestContext или используйте render Представления Django 1.3, основанные на методах или классах, будут содержать объект запроса в вашем шаблоне. Отсюда просто получить доступ к текущему пути и сравнить его с ожидаемыми значениями:

<a href="/some/path/to/be/highlighted/"{% if request.path == '/some/path/to/be/highlighted/' %} class="active"{% endif %}>Some Link</a>

В Django 1.3 мне нравится сохранять избыточность и использовать as оператор для поиска URL:

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

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

Развивая принятый ответ Криса, вы можете использовать тот факт, что язык шаблонов Django поддерживает in для частичного соответствия. Так, например, если у вас есть такие URL, как

/people/directory
/people/profiles/joe
/people/profiles/edit

и вы хотите, чтобы основной навигационный элемент "Люди" выделен для всех этих случаев, используйте что-то вроде:

{% if "/people/" in request.path %}class="active"{% endif %}

Просто подумал, что я добавлю свой подход для других, чтобы рассмотреть, если они найдут это в Google.

В моих шаблонах у меня есть что-то вроде этого:

{% block pagename %}homepage{% endblock %}

Затем в моем основном шаблоне, что-то вроде этого (чтобы имя страницы из шаблона наследования было доступно для отображаемой страницы):

<span id="_pageName" style="display:none">{% block pagename %}{% endblock %}</span>

Мои ссылки выглядят так:

<li data-link-name="homepage"><a href="{% url "pages:home" %}">Home</a></li>

Все, что вам нужно, это немного javascript для применения вашего CSS-класса к правильной ссылке при загрузке страницы. Мой выглядит примерно так:

$(function() {
    var pageName = document.getElementById('_pageName');
    if (pageName != null) { pageName = pageName.innerHTML; }
    else { pageName = ''; }
    if (pageName.length > 0) {
        $("li[data-link-name='" + pageName + "']").addClass('active');
    }
});

Очень просто, дает вам контроль над тем, какую ссылку выделить, добавив крошечный блок в ваши шаблоны.

В другом подобном вопросе я видел ответы jpwatts', 110j' s, 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-страницами или корневой страницей.

Даже проще, чем использовать asоператор (текущий верхний ответ) помещает следующее ifвокруг любых изменений HTML или CSS, которые вы хотите сделать, чтобы показать страницу как активную:

      {% if request.resolver_match.url_name == 'your_active_url_pattern_name' %}

Если вы хотите обрабатывать сложные URL-адреса с помощью Unicode, не забудьте использовать iriencode( https://docs.djangoproject.com/en/dev/ref/templates/builtins/#iriencode)

      {% url 'your_view_name_defined_in_urls.py' possible_attribute as url %}
<a class="{% if request.path|iriencode == url %}active{% endif %}" href="{{ url }}">
    Your label
</a>

{% if "/people/" в request.path %}class="active"{% endif %}

Это самое или лучшее решение, вот как реализовать

          {% if "/customer_account" in request.path %}
    <a href="/customer_account" class="item active">
        <div class="col">
            <ion-icon name="person-outline"></ion-icon>
            <strong class="cusb">My Account</strong>
        </div>
    </a>     
    {% else %} 
    <a href="/customer_account" class="item">
        <div class="col">
            <ion-icon name="person-outline"></ion-icon>
            <strong class="cusb">My Account</strong>
        </div>
    </a>
    {% endif %}

В продолжение ответа fabspro, вот способ сделать это на основе URL страниц и с помощью vanilla js.

<div id="navbar">
    <ul>
        <li data-link-name="home">
            <a href="{% url 'home' %}"><span>Home</span></a>
        </li>
        <li data-link-name="parent">
            <a href="{% url 'myapp:index' %}"><span>Parent</span></a>
        </li>
        <li data-link-name="child1">
            <a href="/myapp/child1/grandchild1"><span>Child 1</span></a>
        </li>
    </ul>
</div>

<script>
    var path = location.pathname;
    if (path == "/") {
        pageName = "home";
    } else if (path.startsWith("/myapp/child1")){
        pageName = "child1";
    } else if (path.startsWith("/myapp")) {
        pageName = "parent";
    }

    document.querySelector("li[data-link-name='" + pageName + "']").classList += "active";
</script>

Здесь много гибкости. Например, Parent ссылка выше будет выделена для всех URL-адресов, кроме /child1, Child 1 ссылка приведет пользователя к /grandchild1 страница, но ссылка будет показана активной для всех grandchildren в child1, Любая логика может быть написана на самом деле.

Другие вопросы по тегам