Navigasi di django

104

Saya baru saja membuat webapp kecil pertama saya di Django dan saya menyukainya. Saya akan mulai mengubah situs PHP produksi lama menjadi django dan sebagai bagian dari templatnya, terdapat bilah navigasi.

Di PHP, saya memeriksa setiap URL opsi nav terhadap URL saat ini, di kode template dan menerapkan kelas CSS jika mereka berbaris. Ini sangat berantakan.

Apakah ada yang lebih baik untuk django atau cara yang baik untuk menangani kode di templat?

Untuk memulai, bagaimana saya mendapatkan URL saat ini?

Oli
sumber
Saya membuat github.com/orokusaki/django-active-menu untuk ini - mendukung struktur URL bersarang, dan bergantung pada konfigurasi daripada konvensi ( seburuk kedengarannya), sehingga Anda dapat menentukan hierarki situs Anda sesuka Anda. Anda hanya menggunakan <a href="{% url "view:name" %}" {% active_class "view:name" %}>. Anda dapat menggunakannya untuk menghasilkan hanya satu " active"nilai (dengan melewati Falsesebagai argumen kedua untuk tag) untuk append ke atribut kelas yang ada, tetapi untuk sebagian besar link nav bahwa contoh adalah apa yang saya gunakan.
orokusaki
Pertanyaan ini sepertinya terkait dengan yang satu ini stackoverflow.com/a/9801473/5739875
Evgeny Bobkin
Mungkin kisi ini membantu: djangopackages.org/grids/g/navigation
guettli

Jawaban:

74

Saya menggunakan warisan template untuk menyesuaikan navigasi. Sebagai contoh:

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 %}
jpwatts.dll
sumber
Saya sangat menyukai ide ini, terutama untuk fleksibilitas, tetapi ide ini hadir dengan trade-off yang tidak terlalu KERING. Saya memang mulai menggunakan ini di situs.
Pengecut anonim
23
Saya tidak antusias dengan pendekatan ini karena tidak jarang memiliki beberapa bagian situs yang ditangani oleh sub-template yang sama. Jadi Anda akhirnya menempatkan vars kustom dalam tampilan dan kondisional di template, atau menata ulang sub-template sehingga semuanya unik ... semua hanya untuk mendeteksi bagian situs saat ini. Pendekatan tag template akhirnya menjadi lebih bersih pada akhirnya.
shacker
Saya melihat beberapa solusi lain, dan sepertinya semuanya sedikit hack. Yang ini, setidaknya, cukup mudah dan sederhana untuk diimplementasikan / dihapus.
mlissner
Saya refactored <ul id="nav">....</ul>ke file yang berbeda, katakanlah tabs.html. Jadi sekarang base.html berisi {%block nav%}{%include "tabs.html"%}{%endblock%}dan kemudian sorotan dari tab aktif berhenti bekerja (di about.html di atas). Apakah saya melewatkan sesuatu?
None-da
@Maddy Anda memiliki cukup banyak tipuan yang terjadi sehingga saya tidak sepenuhnya yakin saya menyimpannya langsung di kepala saya, tetapi saya pikir jawabannya berkaitan dengan cara kerja includetag. Lihat catatan yang disertakan dalam dokumen: docs.djangoproject.com/en/dev/ref/templates/builtins/#include Dalam kasus Anda, pada saat Anda mencoba mengganti template dasar about.html, saya rasa Anda sudah sudah mendapat blok HTML yang telah dirender, daripada blok cetakan Django menunggu untuk diproses.
jpwatts
117

Anda tidak perlu jika untuk melakukan itu, lihat kode berikut:

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>

itu dia. untuk detail implementasi, lihat:
gnuvince.wordpress.com
110j.wordpress.com

pradyunsg
sumber
2
Properti href kehilangan tanda kurung template django {{,}}. Misalnya, <a class="{% active request home %}" href="home"> Home </a> haruslah, <a class = "{% active request home%}" href = "{{home} } "> Beranda </a> file tags.py juga membutuhkan beberapa penyertaan. Jika tidak, solusi yang bagus!
bsk
2
+1 Ini lebih longgar digabungkan dari aplikasi. Sebagai pemula, saya menemukan tag membutuhkan aplikasinya sendiri, Anda tidak bisa begitu saja membuangnya ke file tags.py global. Saya membuat aplikasi baru yang disebut tag dan semuanya berjalan lancar. docs.djangoproject.com/en/dev/howto/custom-template-tags
Keyo
3
@Keyo, buat direktori templatetags di proyek Anda, dan tambahkan proyek Anda ke aplikasi yang diinstal. Itu juga akan berhasil. Atau, seperti yang Anda katakan, buat situs utama Anda sebagai aplikasi dalam proyek Anda.
Josh Smeaton
5
Jangan lupa untuk menambahkan django.core.context_processors.requestke Anda TEMPLATE_CONTEXT_PROCESSORSdisettings.py
amigcamel
1
Ini tidak valid untuk negara bagian yang mungkin bersarang, misalnya mysite.com(sebagai rumah) dan mysite.com/blog, karena jalur akan ditampilkan sebagai /dan /blog/(masing-masing) menghasilkan kecocokan untuk yang pertama setiap kali. Jika Anda tidak menggunakan /sebagai pendaratan, itu mungkin baik-baik saja jika tidak saya hanya menggunakan return 'active' if pattern == request.path else ''(saya belum melihat masalah dengan ini, tetapi saya hanya mengatur menggunakan ini).
nerdwaller
33

Saya menyukai kebersihan 110j di atas jadi saya mengambil sebagian besar dan memfaktorkan ulang untuk menyelesaikan 3 masalah yang saya miliki dengannya:

  1. ekspresi reguler mencocokkan url 'beranda' dengan yang lainnya
  2. Saya membutuhkan beberapa URL yang dipetakan ke satu tab navigasi , jadi saya membutuhkan tag yang lebih kompleks yang menggunakan jumlah parameter yang bervariasi
  3. memperbaiki beberapa masalah url

Ini dia:

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>
nivhab.dll
sumber
Ini mungkin jawaban terbaik kita dengan Marcus one, tapi bagaimana cara kerjanya dengan "rumah"? itu selalu aktif? Bagaimana cara membuatnya aktif hanya di root url call (www.toto.com/ dan www.toto.com/index)? Kedua jawaban tidak menghasilkan masalah ini ...
DestyNova
20

Saya penulis garis silsilah django yang saya tulis secara khusus untuk menjawab pertanyaan ini: D

Saya menjadi kesal menggunakan metode jpwatts (yang dapat diterima) dalam proyek saya sendiri dan mendapatkan inspirasi dari jawaban 110j. Silsilah terlihat seperti ini:

{% 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 hanya diganti dengan "aktif" jika argumennya cocok dengan awal URL halaman saat ini.

Argumen variabel, dan {% url %}resolusi terbalik tipe penuh , juga didukung. Saya menaburkan beberapa opsi konfigurasi dan menyempurnakannya sedikit dan mengemasnya untuk digunakan semua orang.

Jika ada yang tertarik, baca lebih lanjut di:

>> github.com/marcuswhybrow/django-lineage

Marcus Whybrow
sumber
1
jalur pengkodean keras ke dalam template :(
CpILL
10

Sejak Django 1.5 :

Dalam semua tampilan berbasis kelas generik (atau tampilan berbasis kelas apa pun yang mewarisi dari ContextMixin), kamus konteks berisi variabel tampilan yang mengarah ke instance View.

Jadi jika Anda menggunakan tampilan seperti itu, Anda dapat menambahkan sesuatu breadcrumbsseperti bidang tingkat kelas dan menggunakannya di templat Anda.

Contoh kode tampilan:

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

Di template Anda, Anda bisa menggunakannya dengan cara ini:

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

Jika Anda ingin "menyorot" item navigasi induk, Anda perlu memperluas breadcrumbsdaftar:

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

... dan di template Anda:

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

Ini adalah solusi yang mudah dan bersih dan bekerja cukup baik dengan navigasi bersarang.

Konrad Hałas
sumber
Dalam contoh itu, bukankah ketiga item navigasi tersebut akan menjadi .active?
Oli
Ya, tetapi ini biasanya yang ingin Anda capai dengan navigasi multi-level. Anda tentu saja dapat memasukkan satu barang breadcrumbsjika Anda mau. Tapi Anda benar - contoh saya bukanlah yang terbaik.
Konrad Hałas
@Oli meningkatkan contoh.
Konrad Hałas
9

Anda bisa menerapkan kelas atau id ke elemen tubuh halaman, daripada ke item navigasi tertentu.

HTML:

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

CSS:

body.home #nav_home,
body.about #nav_about { */ Current nav styles */ }
Michael Warkentin
sumber
8

Saya melakukannya seperti ini:

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

dan kemudian yang harus saya lakukan adalah menambahkan tampilan {'active_tab': 'statistics'}ke kamus konteks saya.

Jika Anda menggunakan RequestContextAnda bisa mendapatkan jalur saat ini di template Anda sebagai:

{{ request.path }}

Dan menurut pandangan Anda:

from django.template import RequestContext

def my_view(request):
    # do something awesome here
    return template.render(RequestContext(request, context_dict))
muhuk
sumber
Terima kasih telah membagikan info ini. Saya menggunakan metode ini, tetapi juga memiliki halaman datar di bilah navigasi saya, jadi untuk mendeteksi dan menyorotnya dengan benar, saya menggunakan {% ifequal flatpage.url '/ about /'%}. Saya tidak suka deteksi URL yang di-hardcode, tetapi berfungsi untuk peretasan sekali saja.
Matt Garrison
Masalah dengan solusi ini adalah Anda memiliki "statistik" yang di-hardcode ke dalam kode. Ini mengalahkan tujuan menggunakan tag url untuk mendapatkan url halaman.
Tepat
7

Saya mengambil kode dari nivhab di atas dan menghapus beberapa kejanggalan dan membuatnya menjadi templatetag yang bersih, memodifikasinya sehingga / akun / edit / akan tetap membuat / akun / tab aktif.

#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 %}
Andreas
sumber
6

Ini hanyalah varian dari solusi css yang diusulkan oleh Toba di atas:

Sertakan berikut ini di template dasar Anda:

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

Kemudian di template Anda yang memperluas penggunaan dasar:

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

Anda kemudian dapat menggunakan css untuk menyorot area saat ini berdasarkan tag tubuh (misalnya jika kami memiliki tautan dengan id nav-home):

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

Anda dapat menggunakan fungsi sebaliknya dengan parameter yang sesuai untuk mendapatkan url saat ini.

Corey
sumber
3

Terima kasih atas jawaban Anda sejauh ini, tuan-tuan. Aku telah melakukan sesuatu yang sedikit berbeda lagi ..

Di template saya:

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

Setelah saya mengetahui halaman mana yang saya masuki dalam logika (biasanya di urls.py), saya meneruskan class="selected"sebagai bagian dari konteks di bawah nama yang tepat ke template.

Misalnya jika saya berada di halaman link1, saya akan menambahkan {'link1_active':' class="selected"'}konteks untuk template untuk mengambil dan menyuntikkan.

Tampaknya berfungsi dan cukup bersih.

Edit: untuk mencegah HTML dari controller / view saya, saya telah memodifikasi ini sedikit:

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

Itu membuat template sedikit kurang dapat dibaca, tetapi saya setuju, lebih baik tidak mendorong HTML mentah dari file url.

Oli
sumber
2
Anda harus benar - benar menghindari penanganan HTML mentah dalam tampilan Anda, yang dibutuhkan oleh teknik ini. Pernahkah Anda berpikir untuk menulis tag template kustom?
Justin Voss
Kamu benar. Saya telah mengedit untuk berhenti melewati HTML. Saya baru saja melewati True sekarang. Saya belum menulis tag template apa pun, tapi ya, ini bisa menjadi tempat yang baik untuk memulai.
Oli
2

Saya memiliki beberapa menu di halaman yang sama yang dibuat secara dinamis melalui loop. Posting di atas yang berkaitan dengan konteks memberi saya perbaikan cepat. Semoga ini bisa membantu seseorang. (Saya menggunakan ini selain tag template aktif - perbaikan saya memecahkan masalah dinamis). Sepertinya perbandingan yang konyol, tetapi berhasil. Saya memilih untuk menamai variabel active_something-unique dan sesuatu-unique, cara ini bekerja dengan menu bersarang.

Berikut ini sebagian dari pandangannya (cukup untuk memahami apa yang saya lakukan):

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

    }

Dan ini dari template:

<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>
Thomas Schreiber
sumber
2

Solusi saya adalah menulis prosesor konteks sederhana untuk mengatur variabel berdasarkan jalur permintaan:

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}

(Jangan lupa untuk menambahkan prosesor kustom Anda ke TEMPLATE_CONTEXT_PROCESSORS di settings.py.)

Kemudian di template dasar saya menggunakan tag ifequal per link untuk menentukan apakah akan menambahkan kelas "aktif". Memang pendekatan ini sangat terbatas pada fleksibilitas struktur jalur Anda, tetapi berfungsi untuk penerapan saya yang relatif sederhana.


sumber
Saya pikir sangat masuk akal untuk memiliki ini dalam konteks global, sehingga Anda dapat mereferensikan bagian situs dengan berbagai cara (menggunakan template yang berbeda untuk bagian situs yang berbeda misalnya. +1
shacker
2

Saya hanya ingin membagikan peningkatan kecil saya ke pos nivhab. Dalam aplikasi saya, saya memiliki subnavigasi dan saya tidak ingin menyembunyikannya hanya dengan menggunakan CSS, jadi saya memerlukan semacam tag "jika" untuk menampilkan subnavigasi suatu item atau tidak.

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

Pada dasarnya Anda dapat menggunakan ini dengan cara yang sama seperti tag aktif:

{% url product_url as product %}

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

Hanya peningkatan lain dari solusi asli.

Ini menerima beberapa pola dan pola yang paling baik juga tanpa nama yang ditulis sebagai URL relatif yang dibungkus dengan '"', seperti berikut:

{% 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 berjalan seperti ini:

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 ""
xaralis.dll
sumber
2

Saya menggunakan jquery untuk menyorot navbar saya. Solusi ini hanya menambahkan kelas css "aktif" ke item yang sesuai dengan pemilih 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>
matts1
sumber
2

Sedikit peningkatan pada jawaban @tback , tanpa %if%tag apa pun :

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

Gunakan di template Anda seperti itu:

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

Dan sertakan "django.core.context_processors.request"dalam TEMPLATE_CONTEXT_PROCESSORSpengaturan Anda .

MadeOfAir
sumber
2

Saya menemukan yang terbaik adalah menggunakan tag inklusi:

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>

Ini hanya item navigasi bootstrap dasar yang ingin saya render.

Itu mendapat nilai href, dan secara opsional nilai link_name. is_activedihitung berdasarkan permintaan saat ini.

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

Kemudian gunakan di navigasi: 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>
Tjorriemorrie
sumber
Hanya bacaan sepintas, tetapi apakah ini tidak membatasi hal-hal menjadi sama persis di URL? Saya biasanya menggunakan petunjuk navigasi seperti ini untuk halaman dalam juga. Misalnya item Tentang nav akan disorot jika Anda berada di salah satu /about/company-history/atau /about/what-we-do/
Oli
1
Ya, tapi is_activebisa diganti dan kunci lain yang ditambahkan ke kamus dikembalikan. Juga, ceknya bisa context.request.resolver_match.url_name.startswith(x)atau apa saja. Juga, Anda dapat memiliki kode sebelum pernyataan return untuk menetapkan nilai dict. Selain itu, Anda dapat menggunakan template yang berbeda, yaitu template untuk top_level_nav.htmldengan logika berbeda, dll.
Tjorriemorrie
Solusi bersih dan sederhana ... bagus!
mmw
1

Sedikit memodifikasi jawaban Andreas, sepertinya Anda dapat meneruskan nama rute dari urls.py ke tag template. Dalam contoh saya my_tasks, dan kemudian dalam fungsi tag template gunakan fungsi reverse untuk mengetahui apa URL yang seharusnya, maka Anda dapat mencocokkannya dengan URL di objek permintaan (tersedia dalam konteks template)

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>
errkk
sumber
Mungkin, pendekatan yang lebih langsung: turnkeylinux.org/blog/django-navbar
jgsogo
1

Saya tahu saya terlambat ke pesta. Saya tidak menyukai salah satu solusi populer:

The metode blok tampaknya salah: Saya pikir navigasi harus mandiri.

The Metode template_tag tampaknya salah: Saya tidak suka bahwa saya harus mendapatkan url dari url-tag pertama. Juga, saya pikir kelas css harus didefinisikan dalam template, bukan tagnya.

Oleh karena itu saya menulis filter yang tidak memiliki kekurangan yang saya jelaskan di atas. Ia kembali Truejika url aktif dan oleh karena itu dapat digunakan dengan {% if %}:

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

Kode:

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

Pastikan untuk menggunakan RequestContextpada halaman dengan navigasi atau untuk mengaktifkan permintaan context_processor disettings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    'django.core.context_processors.request',
)
tback
sumber
1

Saya telah melihat jawaban jpwatts ', 110j , nivhab & Marcus Whybrow , tetapi semuanya tampaknya kurang dalam sesuatu: bagaimana dengan jalur root? Kenapa selalu aktif?

Jadi saya telah membuat cara lain, lebih mudah, yang membuat "pengontrol" memutuskan dengan sendirinya dan menurut saya cara ini menyelesaikan sebagian besar masalah besar.

Ini tag kustom saya:

## myapp_tags.py

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

Kemudian, "controller" mendeklarasikan class CSS yang dibutuhkan (sebenarnya, yang paling penting adalah mendeklarasikan keberadaannya ke template)

## views.py

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

Dan akhirnya, saya merendernya di bilah navigasi saya:

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

Jadi setiap halaman memiliki nilainya sendiri nav_css_classuntuk disetel, dan jika disetel, templat akan merender aktif: tidak perlu requestdalam konteks templat, tidak ada pengupasan URL dan tidak ada lagi masalah tentang halaman multi-URL atau halaman root.

DestyNova
sumber
1

Terinspirasi oleh solusi ini , saya mulai menggunakan pendekatan ini:

**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 %}
Evgeny Bobkin
sumber
0

Inilah tujuan saya. Saya akhirnya menerapkan kelas dalam pandangan saya yang berisi struktur navigasi saya (datar dengan beberapa metadata). Saya kemudian menyuntikkan ini ke templat dan merendernya.

Solusi saya berkaitan dengan i18n. Ini mungkin harus disarikan sedikit lagi tetapi saya tidak terlalu peduli dengan itu.

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)

Saya mendefinisikan logika template menggunakan termasuk seperti ini. Template dasar:

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

Sebenarnya termasuk (termasuk / navigation.html):

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

Semoga seseorang akan merasakan manfaatnya! Saya kira akan sangat mudah untuk memperluas ide itu untuk mendukung hierarki bersarang dll.

Juho Vepsäläinen
sumber
0

Buat template penyertaan "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>

Dan sertakan di elemen 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>

Dan Anda perlu menambahkan ini ke pengaturan:

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

berikut adalah solusi yang cukup sederhana, https://github.com/hellysmile/django-activeurl

Віктор Ковтун
sumber
1
Harap dicatat bahwa Anda harus memposting poin-poin berguna dari sebuah jawaban di sini, di situs ini, atau posting Anda berisiko dihapus sebagai "Bukan Jawaban" . Anda masih dapat menyertakan tautan jika Anda mau, tetapi hanya sebagai 'referensi'. Jawabannya harus berdiri sendiri tanpa memerlukan tautan.
Andrew Barber
0

dari SO Pertanyaan ini

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

Ulangi seperlunya untuk setiap tautan.

suhailvs
sumber
Ini hanya berfungsi untuk pertandingan langsung. Sebagian besar sistem navigasi menandai item navigasi aktif jika halaman turunan juga aktif. Yaitu jika /blog/posts/2021/04/12url item / blog / nav akan aktif.
Oli
@ Oli ya itu tidak akan berhasil beberapa kali. misalnya dalam yaitu navigasi stackoverflow Questions, Tags, Users, Badges, Unanswered, Ask Question. ini tidak akan berhasil Questions, tetapi untuk semua navigasi lain ini akan bekerja dengan baik.
suhailvs
0

Saya juga menggunakan jQuery untuk menyorotnya dan menganggapnya lebih elegan daripada mengacaukan template dengan tag template Django non-semantik.

Kode di bawah ini bekerja dengan dropdown bersarang di bootstrap 3 (menyoroti elemen induk dan anak <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');
    });
});

Ini juga cukup mudah untuk menambahkan clickacara ke return false(atau mengubah hrefatribut ke #) untuk halaman saat ini, tanpa mengubah markup template / 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;
pengguna193130
sumber
0

Saya menggunakan kombinasi dari mixin ini untuk tampilan berbasis kelas:

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

dengan ini di template:

<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>
Brian Faherty
sumber
0

Milik saya agak mirip dengan pendekatan JS lain yang dikirimkan sebelumnya .. hanya tanpa jQuery ...

Katakanlah kita memiliki di base.html yang berikut:

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

Saya baru saja membuat hierarki saya mengikuti pola URL tertentu ... setelah alamat host ... saya memiliki kategori utama saya, misalnya, beranda, berita, analisis, dll. Dan regex hanya menarik kata pertama keluar dari lokasi

Suara Logik
sumber