Навігація в джанго


104

Я тільки що зробив свій перший маленький вебапп у джанго, і мені це подобається. Я збираюся розпочати з перетворення старого виробничого PHP-сайту в django, і як частина його шаблону є панель навігації.

У PHP я перевіряю URL-адресу кожного навігаційного коду на предмет поточної URL-адреси в коді шаблону і застосовую клас CSS, якщо вони вишиковуються в рядку. Це жахливо безладно.

Чи є щось краще для джанго чи хорошого способу обробки коду в шаблоні?

Для початку, як би я пішов про отримання поточної URL-адреси?


Я створив для цього github.com/orokusaki/django-active-menu - він підтримує вкладені структури URL-адрес і покладається на конфігурацію за умовчанням (як недобре це звучить), тож ви можете визначити ієрархію вашого сайту, як тільки захочете. Ви просто використовуєте <a href="{% url "view:name" %}" {% active_class "view:name" %}>. При бажанні ви можете використовувати його для генерації тільки на " active"значенні (шляхом передачі в Falseякості другого аргументу тега) для додавання до існуючого атрибуту класу, але для більшості навігаційних посилань, наприклад , що я використовую.
orokusaki

Це питання, схоже, пов’язане з цим stackoverflow.com/a/9801473/5739875
Євгеній Бобкін

Можливо, ця сітка допомагає: djangopackages.org/grids/g/navigation
guettli

Відповіді:


74

Я використовую спадкування шаблонів для налаштування навігації. Наприклад:

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

Мені ця ідея дуже подобається, особливо за гнучкість, але вона поступається із менш сухим компромісом. Я все-таки почав використовувати це на сайті.
анонімний боягуз

22
Я не в захваті від такого підходу, оскільки не рідкість, щоб декілька розділів сайтів оброблялися одним і тим же підшаблоном. Таким чином, ви, в кінцевому підсумку, вкладаєте власні параметри в представлення та умовні умови в шаблони або переставляєте під шаблони, щоб вони були унікальними ... все лише для виявлення поточного розділу сайту. Підхід до тегів шаблонів зрештою стає більш чистим.
шейкер

Я переглянув кілька інших рішень, і, здається, вони все трохи зламали. Принаймні, цей досить простий і простий у виконанні / брухті.
mlissner

Я <ul id="nav">....</ul>відновив файл до іншого файлу, скажімо, tabs.html. Тож тепер міститься base.html, {%block nav%}{%include "tabs.html"%}{%endblock%}а потім виділення активної вкладки перестало працювати ( приблизно про.html вище). Я щось пропускаю?
None-да

@Maddy У вас достатньо непрямої дії, що я абсолютно не впевнений, що я тримаю це прямо в голові, але я думаю, що відповідь має відношення до того, як includeпрацює тег. Ознайомтеся з приміткою, що міститься в документах: docs.djangoproject.com/en/dev/ref/templates/builtins/#include У вашому випадку до моменту, коли ви намагаєтеся замінити базовий шаблон about.html, я думаю, що ви вже отриманий відредагований HTML-блок, а не блок шаблону Django, який очікує на обробку.
jpwatts

117

Для цього вам не потрібно, перегляньте наступний код:

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


2
У властивостях href відсутні дужки шаблону django {{,}}. Наприклад, <a class="{% активний запит home %}" href="home"> Домашня сторінка </a> повинен бути, <a class = "{% active request home%}" href = "{{home} } "> Домашня сторінка </a> файл tags.py також потребує декількох включень. Інакше чудове рішення!
bsk

2
+1 Це більш вільно пов'язане з програмами. Як початківець я зрозумів, що теги потребують власного додатку, ви не можете просто скинути це у глобальний файл tags.py. Я створив нову програму під назвою теги, і все пройшло гладко. docs.djangoproject.com/en/dev/howto/custom-template-tags
Keyo

3
@Keyo, створіть у вашому проекті каталог шаблонів тегів та додайте проект до installedapps. Це теж зробить трюк. Крім того, як ви сказали, створіть свій основний сайт як додаток у рамках свого проекту.
Джош Смітон

5
Не забудьте додати django.core.context_processors.requestв свій TEMPLATE_CONTEXT_PROCESSORSінsettings.py
amigcamel

1
Це недійсно для станів, які можуть бути вкладені, наприклад mysite.com(як домашній) та mysite.com/blog, як шлях буде показувати, що ( /і /blog/відповідно) дає збіг для першого кожного разу. Якщо ви не використовуєте /як посадка, це може бути нормально, інакше я просто використовую return 'active' if pattern == request.path else ''(я ще не бачив проблем із цим, але я просто налаштував це).
бовдур

33

Мені сподобалася чистота 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>

Може, ми найкраще відповімо з Маркусом одним, але як це працює з "домом"? це завжди активно? Як зробити його активним лише під час кореневого виклику URL-адреси (www.toto.com/ та www.toto.com/index)? Обидві відповіді не спричиняють цієї проблеми ...
DestyNova

20

Я автор автора 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


1
шляхи жорсткого кодування в шаблон :(
CpILL

10

З Джанго 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>

Це просте та чисте рішення та добре працює із вкладеною навігацією.


У цьому прикладі, чи не були б усі три навігаційні елементи .active?
Олі

Так, але це, як правило, ви хочете досягти за допомогою багаторівневої навігації. Звичайно, ви можете помістити один предмет, breadcrumbsякщо хочете. Але ти маєш право - мій приклад не найкращий.
Konrad Hałas

@Oli вдосконалений приклад.
Konrad Hałas

9

Ви можете застосувати клас або id до елемента тіла сторінки, а не до певного елемента навігації.

HTML:

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

CSS:

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

8

Я роблю це так:

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

Дякуємо, що поділилися цією інформацією. Я використовував цей метод, але також мав плоску сторінку в навігаційній смузі, тому щоб виявити це і правильно виділити його, я використовував {% ifequal flatpage.url '/ about /'%}. Мені не подобається жорстке кодування виявлення URL-адреси, але це працює для одноразового злому.
Метт Гаррісон

Проблема з цим рішенням полягає в тому, що у вас є жорсткий код "статистики" в код. Це перешкоджає використанню тегу URL для отримання URL-адреси сторінки.
Джастін

7

Я взяв код з nivhab вище і видалив деяку безтурботність і вніс його в чистий шаблон тега, змінив його, щоб / акаунт / редагувати / все ще зробить / рахунок / вкладку активним.

#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

Це лише варіант рішення 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

Дякую за відповіді поки що, панове Я знову пішов на щось трохи інше ..

У моєму шаблоні:

<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 з файлу URL-адреси.


2
Ви дійсно повинні уникати обробки сирого HTML на ваш погляд, для чого потрібна ця методика. Чи задумалися ви написати тег шаблону?
Джастін Восс

Ти маєш рацію. Я відредагував, щоб перестати проходити HTML. Я просто зараз проходжу через True. Я ще не написав жодних тегів шаблонів, але так, це може бути гарним місцем для початку.
Олі

2

У мене на одній сторінці є декілька меню, які динамічно створюються через цикл. Викладені вище публікації, що стосуються контексту, дали мені швидке виправлення. Сподіваюся, це комусь допомагає. (Я використовую це на додаток до активного тегу шаблону - моє виправлення вирішує динамічну проблему). Це здається дурним порівнянням, але воно працює. Я вирішив назвати змінні 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

Моє рішення полягало в тому, щоб написати простий контекстний процесор для встановлення змінної на основі шляху запиту:

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 у налаштуваннях.py.)

Потім у базовому шаблоні я використовую тег ifequal за посиланням, щоб визначити, чи потрібно додавати клас "активний". Зазначений підхід суворо обмежений гнучкістю вашої структури шляху, але він працює для мого відносно скромного розгортання.


Я думаю, що це дійсно має сенс мати їх у глобальному контексті, тому ви можете посилатися на розділ сайту різними способами (наприклад, використовуючи різні шаблони для різних розділів сайтів. +1.
shacker

2

Я просто хотів поділитися своїм незначним вдосконаленням на посаді nivhab. У моєму додатку є субнавігації, і я не хотів їх приховувати за допомогою лише 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

Просто чергове сповнення оригінального рішення.

Це приймає декілька шаблонів, а також найкраще також безіменні візерунки, записані як відносна 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

Я використовував 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

Невелике покращення щодо відповіді @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налаштування.


2

Я вважав найкращим - використовувати тег включення:

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>

Це лише мій базовий елемент bootstrap nav, який я хочу винести.

Він отримує значення 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,
    }

Потім використовуйте його у nav: 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>

Просто побіжне читання, але чи це не обмежує речі точними відповідностями за URL-адресою? Я зазвичай використовую подібні навігаційні підказки і для глибоких сторінок. Наприклад, пункт «Про нав» буде висвітлено, якби ви були або на одному, /about/company-history/або /about/what-we-do/
Олі,

1
Так, але is_activeможна замінити та повернути інші словники до словника. Також чек може бути context.request.resolver_match.url_name.startswith(x)чи будь-що інше. Крім того, ви можете мати код перед оператором return, щоб встановити значення dict. Крім того, ви можете використовувати різні шаблони, наприклад, для top_level_nav.htmlрізної логіки тощо.
Tjorriemorrie,

Чисте і просте рішення ... приємно!
MMW

1

Трохи змінивши відповідь Андреаса, схоже, ви можете перейти в назві маршруту від 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>

Можливо, більш прямолінійний підхід: turnkeylinux.org/blog/django-navbar
jgsogo

1

Я знаю, що спізнююсь на вечірку. Мені не сподобалось жодне з популярних рішень:

спосіб блоку здається неправильним: Я думаю , що навігація повинна бути самодостатньою.

Метод 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на сторінках з навігацією або включити запит контекст_процесор у вашомуsettings.py

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

1

Я бачив jpwatts ', 110j ' s, nivhab 's та 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-адресами або кореневої сторінки.


1

Надихнувшись цим рішенням , я почав використовувати такий підхід:

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

0

Ось мій погляд на це. Я закінчив реалізувати клас у своїх уявленнях, який містить мою навігаційну структуру (плоскі з деякими метаданими). Потім я ввожу це до шаблону і виводжу його.

Моє рішення стосується 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 "includes/navigation.html" with items=navi %}

Фактично включають (включає / навігація.html):

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

Сподіваємось, хтось знайде це корисним! Я думаю, було б досить легко поширити цю ідею на підтримку вкладених ієрархій тощо.


0

Створіть шаблон включення "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',
)

0

ось досить просте рішення, https://github.com/hellysmile/django-activeurl


1
Зверніть увагу, що ви повинні розмістити корисні пункти відповіді тут, на цьому веб-сайті, інакше ваша публікація ризикує бути видаленою як "Не відповідь" . Ви можете все-таки включити посилання за бажанням, але лише як "довідник". Відповідь має стояти самостійно, не потребуючи посилання.
Ендрю Барбер

0

з цього питання питання

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

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


Це працює лише для прямих матчів. Більшість навігаційних систем позначають елемент навігації активним, якщо активна сторінка нащадка. Тобто, якщо /blog/posts/2021/04/12URL-адресом був би активний / / blog / nav.
Олі

@ Олі так, це не працюватиме кілька разів. наприклад , в StackOverflow навігації , тобто Questions, Tags, Users, Badges, Unanswered, Ask Question. це не буде працювати Questions, але для всіх інших навичок це буде добре.
suhailvs

0

Я також використав jQuery, щоб виділити його та вважати його більш елегантним, ніж захаращування шаблону несемантичними тегами шаблону Django.

Нижче наведений код працює з вкладеними спадними програмами в завантажувальній системі 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's 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;

0

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

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>

0

Моя трохи схожа на інший 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-адреси ... після адреси хоста ... у мене є основна категорія, наприклад, домашня сторінка, новини, аналіз тощо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.