Навигация в Джанго - PullRequest
       44

Навигация в Джанго

97 голосов
/ 04 декабря 2008

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

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

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

Для начала, как мне получить текущий URL?

Ответы [ 29 ]

3 голосов
/ 04 декабря 2008

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

2 голосов
/ 12 февраля 2012

Просто еще одно преимущество оригинального решения.

Это допускает использование нескольких шаблонов и, что лучше всего, также неназванных шаблонов, написанных как относительный 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 ""
2 голосов
/ 09 сентября 2009

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

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 %}
2 голосов
/ 23 мая 2009

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

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 для каждой ссылки, чтобы определить, добавлять ли «активный» класс. Конечно, этот подход строго ограничен гибкостью структуры вашего пути, но он подходит для моего относительно скромного развертывания.

2 голосов
/ 21 апреля 2009

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

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

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>
2 голосов
/ 12 ноября 2012

Я использовал 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>
2 голосов
/ 22 марта 2019

Я нашел, что лучше всего использовать тег включения:

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>

Это просто мой базовый элемент начальной загрузки, который я хочу визуализировать.

Получает значение href и, необязательно, значение link_name. is_active рассчитывается на основе текущего запроса.

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

Тогда используйте его в навигации: 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>
2 голосов
/ 15 февраля 2015

Небольшое улучшение ответа @ 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.

1 голос
/ 02 июня 2012

Немного изменив ответ Андреаса, похоже, вы можете передать имя маршрута от urls.py до тега шаблона. В моем примере my_tasks, а затем в функции тега шаблона используйте функцию reverse, чтобы определить, каким должен быть 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>
1 голос
/ 03 января 2018

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

**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 %}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...