Django'da gezinme


104

Django'daki ilk küçük web uygulamamı yeni yaptım ve çok beğendim. Eski bir PHP üretim sitesini django'ya dönüştürmeye başlamak üzereyim ve şablonunun bir parçası olarak bir gezinme çubuğu var.

PHP'de, şablon kodundaki her nav seçeneğinin URL'sini geçerli URL ile karşılaştırıyorum ve sıralanırlarsa bir CSS sınıfı uyguluyorum. Korkunç derecede dağınık.

Django için daha iyi bir şey veya şablondaki kodu kullanmanın iyi bir yolu var mı?

Başlamak için, mevcut URL'yi nasıl alabilirim?


Bunun için github.com/orokusaki/django-active-menu'yu oluşturdum - iç içe geçmiş URL yapılarını destekliyor ve konvansiyon yerine yapılandırmaya dayanıyor (kulağa ne kadar kötü geliyorsa), böylece sitenizin hiyerarşisini istediğiniz gibi tanımlayabilirsiniz. Sadece kullan <a href="{% url "view:name" %}" {% active_class "view:name" %}>. İsteğe bağlı oluşturmak için kullanabilirsiniz sadece" active" (ileterek değeri Falsevar olan bir sınıf özniteliği için eklerine etikete ikinci argüman olarak), ancak çoğu nav bağlantıları için örnek kullandığım ne olduğunu.
orokusaki


Belki bu ızgara yardımcı olur: djangopackages.org/grids/g/navigation
guettli

Yanıtlar:


74

Gezinmeyi özelleştirmek için şablon devralma kullanıyorum. Örneğin:

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

Bu fikri, özellikle esneklik açısından çok seviyorum, ancak daha az KURU ödünleşimiyle birlikte geliyor. Bunu bir sitede kullanmaya başladım.
anonim korkak

23
Bu yaklaşım konusunda hevesli değilim çünkü aynı alt şablon tarafından birden çok site bölümünün ele alınması alışılmadık bir durum değil. Sonuç olarak, şablonlardaki görünümlere ve koşullara özel değişkenler koyarsınız veya alt şablonları yeniden düzenlersiniz, böylece hepsi benzersiz olur ... hepsi sadece geçerli site bölümünü tespit etmek için. Şablon etiketi yaklaşımı sonunda daha temiz hale gelir.
shacker

Birkaç başka çözüme de baktım ve hepsi biraz hacklenmiş gibi görünüyor. Bu, en azından oldukça basit ve uygulaması / hurdaya çıkarması basit.
mlissner

<ul id="nav">....</ul>farklı bir dosyaya yeniden düzenledim, tabs.html diyelim. Artık base.html dosyası içeriyordu {%block nav%}{%include "tabs.html"%}{%endblock%}ve ardından etkin sekmenin vurgulanması çalışmayı durdurdu (yukarıdaki about.html'de). Bir şey kaçırıyor muyum?
None-da

@Maddy Yeterince yöneltme yapıyorsun, bunu kafamın içinde tuttuğumdan kesinlikle emin değilim, ama cevabın includeetiketin nasıl çalıştığı ile ilgili olduğunu düşünüyorum . Dokümanlarda bulunan nota bakın: docs.djangoproject.com/en/dev/ref/templates/builtins/#include Sizin durumunuzda, temel şablonu geçersiz kılmaya çalıştığınız zaman about.html, sanırım işlenmeyi bekleyen bir Django şablon bloğu yerine zaten işlenmiş bir HTML bloğu var.
jpwatts

117

Bunu yapmak için bir eğer ihtiyacınız yok, aşağıdaki koda bir göz atın:

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>

bu kadar. uygulama detayları için bir göz atın:
gnuvince.wordpress.com
110j.wordpress.com


2
Href özelliklerinde django şablon parantezleri {{,}} eksik. Örneğin, <a class="{% active request home %}" href="home"> Home </a>, <a class = "{% active request home%}" href = "{{home} olmalıdır } "> Ana Sayfa </a> tags.py dosyası da birkaç içeriğe ihtiyaç duyacaktır. Aksi takdirde, harika bir çözüm!
bsk

2
+1 Bu, uygulamalardan daha gevşek bir şekilde birleştirilmiştir. Yeni başlayan biri olarak etiketlerin kendi uygulamasına ihtiyacı olduğunu anladım, bunu global bir tags.py dosyasına aktaramazsınız. Etiketler adında yeni bir uygulama oluşturdum ve her şey sorunsuz gitti. docs.djangoproject.com/en/dev/howto/custom-template-tags
Keyo

3
@Keyo, projenizde bir templatetags dizini oluşturun ve projenizi kurulu uygulamalara ekleyin. Bu aynı zamanda hile yapacak. Alternatif olarak, söylediğiniz gibi, ana sitenizi projenizin içinde bir uygulama olarak oluşturun.
Josh Smeaton

5
Eklemeyi unutmayın django.core.context_processors.requestsizin için TEMPLATE_CONTEXT_PROCESSORSinsettings.py
amigcamel

1
Bu, iç içe geçmiş durumlar için geçersizdir, örneğin mysite.com(ana sayfa olarak) ve mysite.com/blogyol her seferinde birincisi için bir eşleşme olarak /ve /blog/(sırasıyla) göstereceği için. /İniş olarak kullanmazsanız , sorun olmayabilir, aksi takdirde sadece kullanırım return 'active' if pattern == request.path else ''(Bununla ilgili sorunları henüz görmedim, ancak bunu kullanarak kurdum).
nerdwaller

33

Yukarıdaki 110j'nin temizliğini beğendim, bu yüzden çoğunu aldım ve onunla yaşadığım 3 sorunu çözmek için yeniden düzenledim:

  1. normal ifade 'ev' url'sini diğerleriyle eşleştiriyordu
  2. Tek bir gezinme sekmesiyle eşlenmiş birden çok URL'ye ihtiyacım vardı , bu nedenle değişken miktarda parametre alan daha karmaşık bir etikete ihtiyacım vardı
  3. bazı url sorunlarını çözdü

İşte burada:

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>

Belki de en iyisi Marcus'la cevap vermeliyiz, ama "ev" ile nasıl işliyor? her zaman aktif mi? Sadece kök url çağrısında (www.toto.com/ ve www.toto.com/index) nasıl aktif hale getirilir? Her iki cevap da bu soruna neden olmaz ...
DestyNova

20

Ben yazar değilim django-soy Bu soruyu çözmek için özel olarak yazdığı: D

Kendi projelerimde (tamamen kabul edilebilir) jpwatts yöntemini kullanmaktan rahatsız oldum ve 110j'nin cevabından ilham aldım. Soy şuna benzer:

{% 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 bağımsız değişken geçerli sayfa URL'sinin başlangıcıyla eşleşiyorsa, basitçe "etkin" ile değiştirilir.

Değişken argümanlar ve tam {% url %}tip ters çözünürlük de desteklenmektedir. Birkaç konfigürasyon seçeneği serpiştirdim ve biraz detaylandırdım ve herkesin kullanması için paketledim.

İlgilenen varsa, şu adreste biraz daha okuyun:

>> github.com/marcuswhybrow/django-lineage


1
şablona sabit kodlama yolları :(
CpILL

10

Django 1.5'ten beri :

Tüm genel sınıf tabanlı görünümlerde (veya ContextMixin'den devralan herhangi bir sınıf tabanlı görünümde), bağlam sözlüğü, View örneğini işaret eden bir görünüm değişkeni içerir.

Dolayısıyla, bu tür görünümleri kullanıyorsanız, breadcrumbssınıf düzeyinde bir alan olarak benzer bir şey ekleyebilir ve şablonlarınızda kullanabilirsiniz.

Örnek görünüm kodu:

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

Şablonunuzda bunu şu şekilde kullanabilirsiniz:

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

Üst gezinme öğelerini ek olarak "vurgulamak" istiyorsanız, breadcrumbslisteyi genişletmeniz gerekir :

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

... ve şablonunuzda:

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

Bu kolay ve temiz bir çözümdür ve iç içe geçmiş gezinme ile oldukça iyi çalışır.


Bu örnekte, üç gezinme öğesinin tümü olmaz mıydı .active?
Oli

Evet, ancak bu genellikle çok seviyeli gezinmeyle elde etmek istediğiniz şeydir. Elbette breadcrumbsisterseniz bir parça da koyabilirsiniz . Ama haklısın - örneğim en iyisi değil.
Konrad Hałas

@Oli geliştirilmiş örnek.
Konrad Hałas

9

Belirli bir gezinme öğesi yerine sayfanın gövde öğesine bir sınıf veya kimlik uygulayabilirsiniz.

HTML:

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

CSS:

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

8

Bunu böyle yapıyorum:

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

ve sonra tek yapmam gereken benim {'active_tab': 'statistics'}görüşüme göre bağlam sözlüğüme eklemek .

Eğer kullanıyorsanız RequestContext, şablonunuzda mevcut yolu şu şekilde alabilirsiniz:

{{ request.path }}

Ve size göre:

from django.template import RequestContext

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

Bu bilgiyi paylaştığınız için teşekkürler. Bu yöntemi kullandım, ancak gezinti çubuğumda bir düz sayfa da vardı, bu yüzden bunu tespit etmek ve doğru şekilde vurgulamak için {% ifequal flatpage.url '/ about /'%} kullandım. URL'nin sabit kodlanmış tespitini sevmiyorum, ancak bir kereye mahsus bir saldırı için çalışıyor.
Matt Garrison

Bu çözümle ilgili sorun, "istatistikleri" kod içine gömmüş olmanızdır. Bu, sayfanın url'sini almak için url etiketini kullanma amacını ortadan kaldırır.
justin

7

Kodu yukarıdaki nivhab'dan aldım ve bazı tuhaflıkları giderdim ve temiz bir şablon etiketi haline getirdim, / account / edit / hala / account / tab etkin olacak şekilde değiştirdim.

#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

Bu, yukarıda Toba tarafından önerilen css çözümünün sadece bir çeşididir:

Aşağıdakileri temel şablonunuza ekleyin:

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

Ardından, temel kullanımı genişleten şablonlarınızda:

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

Daha sonra mevcut alanı body etiketine göre vurgulamak için css kullanabilirsiniz (örneğin, nav-home kimliğine sahip bir bağlantımız varsa):

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


3

Şimdiye kadarki cevaplarınız için teşekkürler beyler. Yine biraz farklı bir şeye gittim ..

Şablonumda:

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

Mantıkta (genellikle urls.py'de) hangi sayfada olduğumu belirledikten class="selected"sonra, içeriğin bir parçası olarak doğru adın altında şablona geçiyorum.

Örneğin, link1 sayfasındaysam, {'link1_active':' class="selected"'}şablonun kapsamını genişletmek ve enjekte etmek için bağlama ekleyeceğim .

Çalışıyor gibi görünüyor ve oldukça temiz.

Düzenleme: HTML'yi denetleyicimin / görünümümün dışında tutmak için bunu biraz değiştirdim:

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

Şablonu biraz daha az okunabilir hale getirir, ancak kabul ediyorum, urls dosyasından ham HTML'yi aktarmamak daha iyidir.


2
Sen olmalıdır gerçekten bu teknik gereği budur Sizce, ham HTML işleme kaçının. Özel bir şablon etiketi yazmayı düşündünüz mü?
Justin Voss

Haklısın. HTML'den geçmeyi durdurmak için düzenleme yaptım. Şimdi True'dan geçiyorum. Henüz herhangi bir şablon etiketi yazmadım, ancak evet, burası başlamak için iyi bir yer olabilir.
Oli

2

Aynı sayfada, bir döngü aracılığıyla dinamik olarak oluşturulan birden çok menüm var. Bağlamla ilgili yukarıdaki gönderiler bana hızlı bir düzeltme sağladı. Umarım bu birine yardımcı olur. (Bunu aktif şablon etiketine ek olarak kullanıyorum - düzeltmem dinamik sorunu çözüyor). Aptalca bir karşılaştırma gibi görünüyor ama işe yarıyor. Değişkenleri active_something-unique ve bir-benzersiz olarak adlandırmayı seçtim, bu şekilde iç içe menülerle çalışıyor.

İşte görünümün bir kısmı (ne yaptığımı anlamak için yeterli):

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

    }

Ve bu şablondan:

<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

Çözümüm, istek yoluna göre bir değişken ayarlamak için basit bir bağlam işlemcisi yazmaktı:

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}

(Özel işlemcinizi settings.py'de TEMPLATE_CONTEXT_PROCESSORS'a eklemeyi unutmayın.)

Ardından temel şablonda, "active" sınıfının eklenip eklenmeyeceğini belirlemek için bağlantı başına bir ifequal etiketi kullanıyorum. Verilen bu yaklaşım, kesinlikle yol yapınızın esnekliğiyle sınırlıdır, ancak nispeten mütevazı dağıtımım için işe yarar.


Bunlara küresel bağlamda sahip olmanın gerçekten mantıklı olduğunu düşünüyorum, böylece site bölümüne çeşitli şekillerde başvurabilirsiniz (örneğin, farklı site bölümleri için farklı şablonlar kullanarak. +1.
shacker

2

Sadece küçük geliştirmemi nivhab'ın gönderisiyle paylaşmak istedim. Uygulamamda alt gezintilerim var ve bunları yalnızca CSS kullanarak gizlemek istemedim, bu yüzden bir öğenin alt gezintisini görüntülemek ya da göstermemek için bir tür "if" etiketine ihtiyacım vardı.

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

Bunu temelde aktif etiketle aynı şekilde kullanabilirsiniz:

{% url product_url as product %}

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

2

Orijinal çözümün başka bir ifadesi.

Bu, birden çok kalıbı kabul eder ve en iyisi, aşağıdaki gibi, '"' ile sarılmış göreli URL olarak yazılan adsız kalıplardır:

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

Etiket şu şekildedir:

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

Gezinti çubuklarımı vurgulamak için jquery kullandım. Bu çözüm, css seçiciye uyan öğeye css sınıfını "active" ekler.

<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'in yanıtı üzerinde herhangi bir %if%etiket olmadan küçük bir geliştirme :

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

Bunu şablonunuzda şu şekilde kullanın:

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

Ve ortamınıza dahil "django.core.context_processors.request"edin TEMPLATE_CONTEXT_PROCESSORS.


2

En iyisinin bir dahil etme etiketi kullanmak olduğunu buldum:

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>

Bu, sadece işlemek istediğim temel önyükleme nav öğem.

Href değerini ve isteğe bağlı olarak link_name değerini alır. is_activemevcut talebe göre hesaplanır.

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

Ardından bir gezinme sisteminde kullanın: 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>

Sadece üstünkörü bir okuma, ancak bu, şeyleri URL'deki tam eşleşmelerle sınırlamıyor mu? Derin sayfalarda da genellikle bunun gibi gezinme ipuçlarını kullanırım. Örneğin, Hakkında gezinti öğesi, ya /about/company-history/da /about/what-we-do/
Oli

1
Evet, ancak is_activedeğiştirilebilir ve diğer anahtarlar eklenebilir sözlüğe geri döndü. Ayrıca çek context.request.resolver_match.url_name.startswith(x)veya başka bir şey olabilir. Ayrıca, dict değerlerini oluşturmak için return ifadesinden önce koda sahip olabilirsiniz. Ayrıca, farklı şablonlar da kullanabilirsiniz, örneğin top_level_nav.htmlfarklı mantık için bir şablon vb.
Tjorriemorrie

Temiz ve basit çözüm ... güzel!
mmw

1

Andreas'ın cevabını biraz değiştirerek, rotanın adını urls.py'den şablon etiketine geçirebileceğiniz görülüyor. Örneğimde my_tasksve ardından şablon etiketi işlevinde, URL'nin ne olması gerektiğini hesaplamak için ters işlevini kullanın, ardından bunu istek nesnesindeki URL ile eşleştirebilirsiniz (şablon bağlamında mevcuttur)

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>

Belki, daha basit bir yaklaşım: turnkeylinux.org/blog/django-navbar
jgsogo

1

Partiye geç kaldığımı biliyorum. Yine de popüler çözümlerin hiçbirini beğenmedim:

Blok yöntemi yanlış görünüyor: Ben navigasyon müstakil olması gerektiğini düşünüyorum.

Template_tag yöntemi yanlış görünüyor: I do not ben ilk url-etiketinden url almak zorunda böyle. Ayrıca, css sınıfının etikette değil şablonda tanımlanması gerektiğini düşünüyorum.

Bu nedenle, yukarıda anlattığım dezavantajlara sahip olmayan bir filtre yazdım. TrueBir url etkinse döner ve bu nedenle aşağıdakilerle kullanılabilir {% if %}:

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

Kod:

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

Yalnızca RequestContextgezinme içeren sayfalarda kullandığınızdan veya sayfanızda bağlam_işlemci isteğini etkinleştirdiğinizden emin olun .settings.py

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

1

Gördüğüm jpwatts ' 110J ' ın, nivhab 'ın & Marcus Whybrow ' ın cevabı, ama hepsi bir şey olmaması gibi görünüyor: Ne kökü yolu hakkında? Neden her zaman aktif?

Bu yüzden başka bir yolu daha kolay hale getirdim, bu da "denetleyicinin" kendi başına karar vermesini ve büyük sorunların çoğunu çözdüğünü düşünüyorum.

İşte benim özel etiketim:

## myapp_tags.py

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

Daha sonra, "denetleyici" gerekli CSS sınıflarını bildirir (aslında, en önemlisi, varlığını şablona bildirmesidir)

## views.py

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

Ve son olarak, onu gezinme çubuğumda oluşturuyorum

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

Bu nedenle, her sayfanın nav_css_classayarlanacak kendi değeri vardır ve ayarlanırsa, şablon etkin hale gelir: requestşablon bağlamında gerek yok, URL ayrıştırma yok ve çoklu URL sayfaları veya kök sayfasıyla ilgili daha fazla sorun yok.


1

Bu çözümden ilham alarak şu yaklaşımı kullanmaya başladım:

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

İşte benim gidişatım. Görünümlerimde gezinme yapımı içeren bir sınıf uygulamaya başladım (bazı meta verilerle düz). Daha sonra bunu şablona enjekte edip oluşturuyorum.

Çözümüm i18n ile ilgileniyor. Muhtemelen biraz daha soyutlanmalı ama bununla gerçekten uğraşmadım.

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)

Şablon mantığını bunun gibi içerir kullanarak tanımladım. Temel şablon:

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

Gerçek içerme (içerir / navigation.html):

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

Umarım birisi bunu faydalı bulacaktır! Sanırım bu fikri iç içe geçmiş hiyerarşileri vb. Desteklemek için genişletmek oldukça kolay olurdu.


0

Bir "intranet / nav_item.html" dahil etme şablonu oluşturun:

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

Ve nav öğesine ekleyin:

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

Ve bunu ayarlara eklemeniz gerekir:

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


0

bu SO Sorusundan

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

Her bağlantı için gerektiği kadar tekrarlayın.


Bu yalnızca doğrudan eşleşmeler için geçerlidir. Çoğu navigasyon sistemi, bir alt sayfa da etkinse nav öğesini etkin olarak işaretler. Yani /blog/posts/2021/04/12url olsaydı / blog / nav öğesi aktif olurdu.
Oli

@Oli evet bazı zamanlar işe yaramayacak. stackoverflow navigasyon yani örneğin Questions, Tags, Users, Badges, Unanswered, Ask Question. için işe yaramayacak Questions, ancak diğer tüm nav'lar için iyi çalışacak.
suhailvs

0

Ayrıca jQuery'yi vurgulamak ve şablonu anlamsal olmayan Django şablon etiketleriyle karıştırmaktan daha zarif bulmak için kullandım.

Aşağıdaki kod, önyükleme 3'teki iç içe açılan listelerle çalışır (hem üst <li>öğeyi hem de alt öğeyi vurgular .

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

Ayrıca , şablon / html biçimlendirmesini değiştirmeden, geçerli sayfaya bir clicketkinlik eklemek return false(veya hrefözniteliği değiştirmek #) oldukça kolaydır :

        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

Sınıf temelli görünümler için bu karışımın bir kombinasyonunu kullanıyorum:

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

bununla şablonda:

<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

Benimki daha önce sunulan başka bir JS yaklaşımına biraz benziyor .. sadece jQuery olmadan ...

Base.html'de aşağıdakilere sahip olduğumuzu varsayalım:

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

Sadece hiyerarşimi belirli bir URL modelini takip edecek şekilde yaptım ... ana bilgisayar adresinden sonra ... ana kategorim var, ör. Ev, haberler, analiz, vb. Ve normal ifade konumdan ilk kelimeyi çıkarıyor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.