Điều hướng trong django


104

Tôi vừa hoàn thành ứng dụng web nhỏ đầu tiên của mình trong django và tôi thích nó. Tôi sắp bắt đầu chuyển đổi một trang PHP sản xuất cũ thành django và như một phần mẫu của nó, có một thanh điều hướng.

Trong PHP, tôi kiểm tra URL của từng tùy chọn điều hướng so với URL hiện tại, trong mã mẫu và áp dụng một lớp CSS nếu chúng xếp hàng. Nó lộn xộn kinh khủng.

Có thứ gì tốt hơn cho django hoặc một cách tốt để xử lý mã trong mẫu không?

Để bắt đầu, tôi sẽ làm cách nào để lấy URL hiện tại?


Tôi đã tạo github.com/orokusaki/django-active-menu cho việc này - nó hỗ trợ các cấu trúc URL lồng nhau và dựa vào cấu hình theo quy ước (nghe có vẻ ác), vì vậy bạn có thể xác định hệ thống phân cấp trang web của mình theo cách bạn muốn. Bạn chỉ việc sử dụng <a href="{% url "view:name" %}" {% active_class "view:name" %}>. Bạn có thể tùy chọn sử dụng nó để tạo ra chỉ các " active"giá trị (bằng cách đi qua Falsenhư một cuộc tranh luận thứ hai để tag) để append đến một thuộc tính lớp hiện có, nhưng đối với hầu hết các liên kết nav rằng ví dụ là những gì tôi sử dụng.
orokusaki

Câu hỏi này dường như có liên quan đến cái này stackoverflow.com/a/9801473/5739875
Evgeny Bobkin

Có thể lưới này giúp ích: djangopackages.org/grids/g/navigation
guettli

Câu trả lời:


74

Tôi sử dụng kế thừa mẫu để tùy chỉnh điều hướng. Ví dụ:

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

Tôi rất thích ý tưởng này, đặc biệt là về tính linh hoạt, nhưng nó đi kèm với sự đánh đổi ít KHÔ hơn. Tôi đã bắt đầu sử dụng cái này trong một trang web.
vô danh hèn nhát

22
Tôi không hào hứng với cách tiếp cận này vì không có gì lạ khi có nhiều phần trang web được xử lý bởi cùng một mẫu phụ. Vì vậy, bạn kết thúc việc đặt các vars tùy chỉnh trong các chế độ xem và các điều kiện trong các mẫu, hoặc sắp xếp lại các mẫu phụ để chúng đều là duy nhất ... tất cả chỉ để phát hiện phần trang web hiện tại. Cuối cùng, cách tiếp cận thẻ mẫu sẽ trở nên sạch sẽ hơn.
shacker

Tôi đã xem xét một số giải pháp khác và có vẻ như tất cả chúng đều là một chút hack. Điều này, ít nhất, khá đơn giản và đơn giản để thực hiện / phế liệu.
mlissner

Tôi đã cấu trúc lại <ul id="nav">....</ul>thành một tệp khác, giả sử tabs.html. Vì vậy, bây giờ base.html chứa {%block nav%}{%include "tabs.html"%}{%endblock%}và sau đó đánh dấu tab đang hoạt động ngừng hoạt động (trong about.html ở trên). Tôi có thiếu gì không?
None-da

@Maddy Bạn đã có đủ điều hướng đang diễn ra mà tôi không hoàn toàn chắc chắn rằng tôi đang giữ nó thẳng trong đầu, nhưng tôi nghĩ câu trả lời liên quan đến cách includehoạt động của thẻ. Kiểm tra ghi chú có trong tài liệu: docs.djangoproject.com/en/dev/ref/templates/builtins/#include Trong trường hợp của bạn, vào thời điểm bạn đang cố gắng ghi đè lên mẫu cơ sở about.html, tôi nghĩ bạn đã đã có một khối HTML được kết xuất, thay vì một khối mẫu Django đang chờ xử lý.
jpwatts

117

Bạn không cần nếu để làm điều đó, hãy xem đoạn mã sau:

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>

đó là nó. để biết chi tiết triển khai, hãy xem tại:
gnuvince.wordpress.com
110j.wordpress.com


2
Thuộc tính của href thiếu dấu ngoặc vuông của mẫu django {{,}}. Ví dụ: <a class="{% active request home %}" href="home"> Home </a> phải là <a class = "{% active request home%}" href = "{{home} } "> Trang chủ </a> tệp tags.py cũng sẽ cần một số tệp bao gồm. Nếu không, giải pháp tuyệt vời!
bsk

2
+1 Điều này được kết hợp lỏng lẻo hơn từ các ứng dụng. Là một người mới bắt đầu, tôi đã phát hiện ra rằng các thẻ cần có ứng dụng riêng, bạn không thể chỉ đưa nó vào một tệp tags.py toàn cục. Tôi đã tạo một ứng dụng mới có tên là thẻ và mọi thứ diễn ra suôn sẻ. docs.djangoproject.com/en/dev/howto/custom-template-tags
Keyo

3
@Keyo, tạo một thư mục templatetags trong dự án của bạn và thêm dự án của bạn vào các ứng dụng đã cài đặt. Điều đó cũng sẽ thực hiện thủ thuật. Ngoài ra, như bạn đã nói, hãy tạo trang web chính của bạn dưới dạng một ứng dụng trong dự án của bạn.
Josh Smeaton

5
Đừng quên thêm django.core.context_processors.requestcho bạn TEMPLATE_CONTEXT_PROCESSORStrongsettings.py
amigcamel

1
Điều này không hợp lệ đối với các trạng thái có thể được lồng vào nhau, ví dụ mysite.com(như trang chủ) và mysite.com/blog, vì đường dẫn sẽ hiển thị //blog/(tương ứng) mang lại kết quả phù hợp với đường dẫn trước đó mỗi lần. Nếu bạn không sử dụng /làm mục đích, điều đó có thể ổn nếu không tôi chỉ sử dụng return 'active' if pattern == request.path else ''(Tôi chưa thấy vấn đề với điều này, nhưng tôi chỉ thiết lập bằng cách sử dụng này).
nerdwaller

33

Tôi thích sự sạch sẽ của 110j ở trên vì vậy tôi đã sử dụng hầu hết nó và cấu trúc lại để giải quyết 3 vấn đề tôi gặp phải với nó:

  1. biểu thức chính quy khớp với url 'home' với tất cả những người khác
  2. Tôi cần nhiều URL được ánh xạ tới một tab điều hướng , vì vậy tôi cần một thẻ phức tạp hơn có lượng thông số thay đổi
  3. đã khắc phục một số sự cố url

Nó đây:

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>

Có thể chúng ta trả lời tốt nhất với Marcus một, nhưng nó hoạt động như thế nào với "nhà"? nó luôn hoạt động? Làm cách nào để chỉ hoạt động khi gọi url gốc (www.toto.com/ và www.toto.com/index)? Cả hai câu trả lời đều không dẫn đến vấn đề này ...
DestyNova

20

Tôi là tác giả của dòng dõi django mà tôi đã viết riêng để giải quyết câu hỏi này: D

Tôi đã trở nên khó chịu khi sử dụng phương pháp jpwatts (hoàn toàn có thể chấp nhận được) trong các dự án của riêng mình và lấy cảm hứng từ câu trả lời của 110j. Dòng dõi trông như thế này:

{% 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 chỉ được thay thế bằng "hoạt động" nếu đối số khớp với phần đầu của URL trang hiện tại.

Các đối số biến và {% url %}độ phân giải đảo ngược kiểu đầy đủ cũng được hỗ trợ. Tôi rắc vào một vài tùy chọn cấu hình và bổ sung một ít và đóng gói để mọi người sử dụng.

Nếu ai quan tâm, hãy đọc thêm một chút về nó tại:

>> github.com/marcuswhybrow/django-lineage


1
đường dẫn mã hóa cứng vào mẫu :(
CpILL

10

Kể từ Django 1.5 :

Trong tất cả các dạng xem dựa trên lớp chung (hoặc bất kỳ dạng xem dựa trên lớp nào kế thừa từ ContextMixin), từ điển ngữ cảnh chứa một biến dạng xem trỏ đến thể hiện Dạng xem.

Vì vậy, nếu bạn đang sử dụng các dạng xem như vậy, bạn có thể thêm một cái gì đó likie breadcrumbslàm trường cấp lớp và sử dụng nó trong các mẫu của bạn.

Mã chế độ xem mẫu:

class YourDetailView(DetailView):
     breadcrumbs = ['detail']
     (...)

Trong mẫu của bạn, bạn có thể sử dụng nó theo cách này:

<a href="/detail/" {% if 'detail' in view.breadcrumbs %}class="active"{% endif %}>Detail</a>

Nếu bạn muốn "đánh dấu" thêm các mục điều hướng dành cho cha mẹ, bạn cần mở rộng breadcrumbsdanh sách:

class YourDetailView(DetailView):
     breadcrumbs = ['dashboard', 'list', 'detail']
     (...)

... và trong mẫu của bạn:

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

Đây là giải pháp dễ dàng và sạch sẽ và hoạt động khá tốt với điều hướng lồng nhau.


Trong ví dụ đó, không phải cả ba mục điều hướng .active?
Oli

Có, nhưng đây thường là những gì bạn muốn đạt được với điều hướng nhiều cấp. Tất nhiên bạn có thể đặt một mục vào breadcrumbsnếu bạn muốn. Nhưng bạn có quyền - ví dụ của tôi không phải là ví dụ tốt nhất.
Konrad Hałas

Ví dụ cải tiến @Oli.
Konrad Hałas

9

Bạn có thể áp dụng một lớp hoặc id cho phần tử nội dung của trang, thay vì cho một mục điều hướng cụ thể.

HTML:

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

CSS:

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

8

Tôi làm như thế này:

<a class="tab {% ifequal active_tab "statistics" %}active{% endifequal %}" href="{% url Member.Statistics %}">Statistics</a>

và sau đó tất cả những gì tôi phải làm là thêm {'active_tab': 'statistics'}vào từ điển ngữ cảnh của tôi trong chế độ xem .

Nếu bạn đang sử dụng, RequestContextbạn có thể lấy đường dẫn hiện tại trong mẫu của mình như:

{{ request.path }}

Và theo quan điểm của bạn:

from django.template import RequestContext

def my_view(request):
    # do something awesome here
    return template.render(RequestContext(request, context_dict))

Cảm ơn vì đã chia sẻ thông tin này. Tôi đã sử dụng phương pháp này nhưng cũng có một trang phẳng trong thanh điều hướng, vì vậy, để phát hiện và đánh dấu nó một cách chính xác, tôi đã sử dụng {% ifequal flatpage.url '/ about /'%}. Tôi không thích việc phát hiện mã cứng của URL, nhưng nó hoạt động cho một lần hack.
Matt Garrison

Vấn đề với giải pháp này là bạn có "thống kê" được mã hóa cứng vào mã. Điều này đánh bại mục đích của việc sử dụng thẻ url để lấy url của trang.
justin

7

Tôi đã lấy mã từ nivhab ở trên và loại bỏ một số tính năng héo và biến nó thành một thẻ tạm thời sạch, sửa đổi nó để / account / edit / vẫn làm cho / account / tab hoạt động.

#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

Đây chỉ là một biến thể của giải pháp css do Toba đề xuất ở trên:

Bao gồm những điều sau đây trong mẫu cơ sở của bạn:

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

Sau đó, trong các mẫu của bạn mở rộng việc sử dụng cơ sở:

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

Sau đó, bạn có thể sử dụng css để đánh dấu khu vực hiện tại dựa trên thẻ body (ví dụ: nếu chúng tôi có liên kết với id là nav-home):

#section-home a#nav-home{
 font-weight:bold;
}


3

Cảm ơn cho câu trả lời của bạn cho đến nay, gents. Tôi lại đi tìm một thứ hơi khác ..

Trong mẫu của tôi:

<li{{ link1_active }}>...link...</li>
<li{{ link2_active }}>...link...</li>
<li{{ link3_active }}>...link...</li>
<li{{ link4_active }}>...link...</li>

Khi tôi đã tìm hiểu logic mà tôi đang truy cập trang nào (thường là trong urls.py), tôi chuyển class="selected"như một phần của ngữ cảnh dưới tên phù hợp vào mẫu.

Ví dụ: nếu tôi đang ở trang link1, tôi sẽ thêm vào {'link1_active':' class="selected"'} vào ngữ cảnh cho mẫu để lấy và đưa vào.

Nó dường như hoạt động và khá sạch sẽ.

Chỉnh sửa: để giữ HTML khỏi bộ điều khiển / chế độ xem của tôi, tôi đã sửa đổi điều này một chút:

<li{% if link1_active %} class="selected"{% endif %}>...link...</li>
<li{% if link2_active %} class="selected"{% endif %}>...link...</li>
...

Nó làm cho mẫu khó đọc hơn một chút, nhưng tôi đồng ý, tốt hơn là không đẩy qua HTML thô từ tệp url.


2
Bạn thực sự nên tránh xử lý HTML thô trong chế độ xem của mình, đó là điều mà kỹ thuật này yêu cầu. Bạn đã nghĩ đến việc viết thẻ mẫu tùy chỉnh chưa?
Justin Voss

Bạn đúng. Tôi đã chỉnh sửa để ngừng chuyển qua HTML. Tôi chỉ đi qua True bây giờ. Tôi chưa viết bất kỳ thẻ mẫu nào, nhưng có, đây có thể là một nơi tốt để bắt đầu.
Oli

2

Tôi có nhiều menu trên cùng một trang được tạo động thông qua một vòng lặp. Các bài đăng ở trên liên quan đến ngữ cảnh đã giúp tôi sửa chữa nhanh chóng. Hy vọng điều này sẽ giúp ai đó. (Tôi sử dụng thẻ này ngoài thẻ mẫu đang hoạt động - bản sửa lỗi của tôi giải quyết được vấn đề động). Nó có vẻ giống như một sự so sánh ngớ ngẩn, nhưng nó hoạt động. Tôi đã chọn đặt tên cho các biến là active_something-unique và something-unique, theo cách này nó hoạt động với các menu lồng nhau.

Đây là một phần của chế độ xem (đủ để hiểu những gì tôi đang làm):

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

    }

Và đây là từ mẫu:

<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

Giải pháp của tôi là viết một bộ xử lý ngữ cảnh đơn giản để đặt một biến dựa trên đường dẫn yêu cầu:

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}

(Đừng quên thêm bộ xử lý tùy chỉnh của bạn vào TEMPLATE_CONTEXT_PROCESSORS trong settings.py.)

Sau đó, trong mẫu cơ sở, tôi sử dụng một thẻ ifequal cho mỗi liên kết để xác định xem có nên thêm lớp "hoạt động" hay không. Được cho là phương pháp này bị giới hạn nghiêm ngặt về tính linh hoạt của cấu trúc đường dẫn của bạn, nhưng nó hoạt động đối với việc triển khai tương đối khiêm tốn của tôi.


Tôi nghĩ thực sự có ý nghĩa nếu có những điều này trong bối cảnh toàn cầu, vì vậy bạn có thể tham khảo phần trang web theo nhiều cách khác nhau (ví dụ: sử dụng các mẫu khác nhau cho các phần trang web khác nhau. +1.
shacker

2

Tôi chỉ muốn chia sẻ cải tiến nhỏ của mình cho bài đăng của nivhab. Trong ứng dụng của mình, tôi có các điều khoản phụ và tôi không muốn ẩn chúng chỉ bằng cách sử dụng CSS, vì vậy tôi cần một số loại thẻ "if" để hiển thị điều khoản phụ cho một mục hoặc không.

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

Về cơ bản, bạn có thể sử dụng điều này theo cách tương tự như thẻ đang hoạt động:

{% url product_url as product %}

{% ifnaviactive request product %}
    <ul class="subnavi">
        <li>Subnavi item for product 1</li>
        ...
    </ul>
{% endifnaviactive %}

2

Chỉ là một giải pháp ban đầu khác.

Điều này chấp nhận nhiều mẫu và tốt nhất là các mẫu không tên được viết dưới dạng URL tương đối được bao bọc trong '"', như sau:

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

Tag như sau:

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

Tôi đã sử dụng jquery để làm nổi bật các thanh điều hướng của mình. Giải pháp này chỉ cần thêm lớp css "hoạt động" vào mục phù hợp với bộ chọn 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

Một chút cải tiến so với câu trả lời của @tback , không có bất kỳ %if%thẻ nào :

# 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 ''

Sử dụng nó trong mẫu của bạn như vậy:

{% load navigation %}
<li class="{{ request|activate_if_active:'url_name' }}">
  <a href="{% url 'url_name' %}">My View</a>
</li>

Và bao gồm "django.core.context_processors.request"trong TEMPLATE_CONTEXT_PROCESSORScài đặt của bạn .


2

Tôi thấy tốt nhất là sử dụng thẻ bao gồm:

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>

Đây chỉ là mục điều hướng bootstrap cơ bản của tôi mà tôi muốn kết xuất.

Nó nhận giá trị href và tùy chọn giá trị link_name. is_activeđược tính toán dựa trên yêu cầu hiện tại.

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

Sau đó, sử dụng nó trong điều hướng: 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>

Chỉ đọc lướt qua, nhưng điều này không giới hạn mọi thứ đối với các kết quả khớp chính xác trên URL? Tôi cũng thường sử dụng các gợi ý điều hướng như thế này cho các trang sâu. Ví dụ: mục Giới thiệu điều hướng sẽ được đánh dấu nếu bạn ở trên /about/company-history/hoặc /about/what-we-do/
Oli

1
Có, nhưng is_activecó thể được thay thế và trả lại các khóa khác vào từ điển. Ngoài ra, séc có thể là context.request.resolver_match.url_name.startswith(x)hoặc bất kỳ thứ gì khác. Ngoài ra, bạn có thể có mã trước câu lệnh trả về để thiết lập các giá trị dict. Ngoài ra, bạn có thể sử dụng các mẫu khác nhau, ví dụ: một cho top_level_nav.htmlvới logic khác nhau, vv
Tjorriemorrie

Giải pháp sạch sẽ và đơn giản ... tốt đẹp!
mmw

1

Sửa đổi một chút câu trả lời của Andreas, có vẻ như bạn có thể chuyển tên của tuyến đường từ urls.py vào thẻ mẫu. Trong ví dụ của tôi my_tasks, sau đó trong hàm thẻ mẫu, hãy sử dụng hàm đảo ngược để tìm ra URL nên là gì, sau đó bạn có thể so khớp URL đó với URL trong đối tượng yêu cầu (có sẵn trong ngữ cảnh mẫu)

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>

Có lẽ, một cách tiếp cận đơn giản hơn: turnkeylinux.org/blog/django-navbar
jgsogo

1

Tôi biết tôi đến muộn bữa tiệc. Tôi không thích bất kỳ giải pháp phổ biến nào:

Các phương pháp khối có vẻ như sai: Tôi nghĩ điều hướng nên khép kín.

Các phương pháp template_tag vẻ như sai: Tôi không thích điều đó tôi phải lấy url từ url-tag đầu tiên. Ngoài ra, tôi nghĩ rằng lớp css nên được xác định trong mẫu, không phải thẻ.

Do đó, tôi đã viết một bộ lọc không có những nhược điểm mà tôi đã mô tả ở trên. Nó trả về Truenếu url đang hoạt động và do đó có thể được sử dụng với {% if %}:

{% load navigation %}
<li{% if request|active:"home" %} class="active"{% endif %}><a href="{% url "home" %}">Home</a></li>

Mật mã:

@register.filter(name="active")
def active(request, url_name):
    return resolve(request.path_info).url_name == url_name

Chỉ cần đảm bảo sử dụng RequestContexttrên các trang có điều hướng hoặc bật bộ xử lý yêu cầu context_processor trongsettings.py

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

1

Tôi đã xem jpwatts ', 110j ' s, nivhab 's & Marcus Whybrow câu trả lời của , nhưng tất cả chúng dường như thiếu một thứ: còn đường dẫn gốc thì sao? Tại sao nó luôn hoạt động?

Vì vậy, tôi đã thực hiện một cách khác, dễ dàng hơn, khiến "bộ điều khiển" tự quyết định và tôi nghĩ nó giải quyết hầu hết các vấn đề lớn.

Đây là thẻ tùy chỉnh của tôi:

## myapp_tags.py

@register.simple_tag
def nav_css_class(page_class):
    if not page_class:
        return ""
    else:
        return page_class

Sau đó, "controller" khai báo các lớp CSS cần thiết (trên thực tế, điều quan trọng nhất là nó khai báo sự hiện diện của nó với mẫu)

## views.py

def ping(request):
    context={}
    context["nav_ping"] = "active"
    return render(request, 'myapp/ping.html',context)

Và cuối cùng, tôi kết xuất nó trong thanh điều hướng của mình:

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

Vì vậy, mỗi trang có nav_css_classgiá trị riêng để đặt và nếu được đặt, mẫu sẽ hoạt động: không cần requesttrong ngữ cảnh mẫu, không phân vùng URL và không còn vấn đề gì về các trang nhiều URL hoặc trang gốc.


1

Lấy cảm hứng từ giải pháp này , tôi bắt đầu sử dụng phương pháp này:

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

Đây là cách của tôi. Tôi đã kết thúc việc triển khai một lớp trong các dạng xem của mình có chứa cấu trúc điều hướng của tôi (phẳng với một số siêu dữ liệu). Sau đó, tôi đưa nó vào mẫu và kết xuất nó.

Giải pháp của tôi liên quan đến i18n. Nó có lẽ nên được tóm tắt nhiều hơn một chút nhưng tôi thực sự không thực sự bận tâm đến điều đó.

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)

Tôi đã xác định logic mẫu bằng cách sử dụng bao gồm như thế này. Mẫu cơ sở:

{% include "includes/navigation.html" with items=navi %}

Thực tế bao gồm (bao gồm / navigation.html):

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

Hy vọng rằng ai đó sẽ thấy điều này hữu ích! Tôi đoán sẽ khá dễ dàng để mở rộng ý tưởng đó để hỗ trợ các cấu trúc phân cấp lồng nhau, v.v.


0

Tạo mẫu bao gồm "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>

Và bao gồm nó trong phần tử điều hướng:

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

Và bạn cần thêm điều này vào cài đặt:

from django.conf import global_settings
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
    'django.core.context_processors.request',
)

0

đây là giải pháp khá đơn giản, https://github.com/hellysmile/django-activeurl


1
Xin lưu ý rằng bạn nên đăng những điểm hữu ích của câu trả lời ở đây, trên trang web này, nếu không bài đăng của bạn có nguy cơ bị xóa là "Không phải câu trả lời" . Bạn vẫn có thể bao gồm liên kết nếu bạn muốn, nhưng chỉ như một 'tài liệu tham khảo'. Câu trả lời sẽ tự đứng mà không cần liên kết.
Andrew Barber

0

từ câu hỏi SO này

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

Lặp lại khi cần thiết cho mỗi liên kết.


Điều này chỉ hoạt động cho các trận đấu trực tiếp. Hầu hết các hệ thống điều hướng đánh dấu mục điều hướng đang hoạt động nếu trang con cũng đang hoạt động. Tức /blog/posts/2021/04/12là nếu là url thì mục / blog / nav sẽ hoạt động.
Oli

@Oli vâng, nó sẽ không hoạt động một số lần. ví dụ như trong stackoverflow navigation tức Questions, Tags, Users, Badges, Unanswered, Ask Question. nó sẽ không hoạt động cho Questions, nhưng đối với tất cả các nav khác, nó sẽ hoạt động tốt.
suhailvs

0

Tôi cũng sử dụng jQuery để làm nổi bật nó và thấy nó thanh lịch hơn là làm lộn xộn mẫu với các thẻ mẫu Django không có ngữ nghĩa.

Đoạn mã dưới đây hoạt động với danh sách thả xuống lồng nhau trong bootstrap 3 (đánh dấu cả phần tử cha và <li>phần tử con .

// 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');
    });
});

Cũng khá dễ dàng để thêm một clicksự kiện vào return false(hoặc thay đổi hrefthuộc tính thành #) cho trang hiện tại mà không cần thay đổi đánh dấu mẫu / 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

Tôi sử dụng kết hợp mixin này cho các chế độ xem dựa trên lớp:

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

với cái này trong mẫu:

<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

Của tôi hơi giống với một cách tiếp cận JS khác đã được gửi trước đây .. chỉ cần không có jQuery ...

Giả sử chúng tôi có trong base.html những điều sau:

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

Tôi vừa tạo hệ thống phân cấp của mình theo một mẫu URL nhất định ... sau địa chỉ máy chủ ... tôi có danh mục chính của mình, ví dụ: nhà riêng, tin tức, phân tích, v.v. và regex chỉ kéo từ đầu tiên ra khỏi vị trí

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.