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

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

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

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

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

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

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

Ответы [ 29 ]

113 голосов
/ 25 января 2009

Если для этого вам не нужно, взгляните на следующий код:

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

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

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

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 %}
32 голосов
/ 18 марта 2009

Мне понравилась чистота выше 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>
18 голосов
/ 11 апреля 2013

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

Меня раздражало использование (вполне приемлемого) метода jpwatts в моих собственных проектах, и я черпал вдохновение в ответе 110j. Происхождение выглядит так:

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

10 голосов
/ 26 сентября 2013

С Джанго 1,5 :

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

Так что, если вы используете такие представления, вы можете добавить что-то вроде 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>

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

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

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

HTML:

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

CSS:

body.home #nav_home,
body.about #nav_about { */ Current nav styles */ }
8 голосов
/ 06 декабря 2008

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

<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))
7 голосов
/ 26 ноября 2009

Я взял код из nivhab выше, удалил некоторые странности и превратил его в чистый тег шаблона, изменил его так, чтобы / 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 %}
6 голосов
/ 07 декабря 2009

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

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

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

Тогда в ваших шаблонах, расширяющих базовое использование:

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

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

#section-home a#nav-home{
 font-weight:bold;
}
3 голосов
/ 05 декабря 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...