ジャンゴでのナビゲーション


104

私は最初の小さなwebappをdjangoで実行したばかりで、気に入っています。古いプロダクションPHPサイトをdjangoに変換するところから始めます。テンプレートの一部として、ナビゲーションバーがあります。

PHPでは、テンプレートコードで現在のURLに対して各navオプションのURLをチェックし、一致する場合はCSSクラスを適用します。それは恐ろしく厄介です。

djangoにもっと良いもの、またはテンプレートのコードを処理する良い方法はありますか?

まず、現在のURLを取得するにはどうすればよいですか?


私はこれのためにgithub.com/orokusaki/django-active-menuを作成しました-ネストされたURL構造をサポートし、慣習よりも構成に依存しているので(そのように悪い)、サイトの階層を好きなように定義できます。あなただけを使用します<a href="{% url "view:name" %}" {% active_class "view:name" %}>。必要に応じて生成するために使用することができ、単に" active"(渡すことで値をFalse例は、私が使用するものであることが、ほとんどのナビゲーションリンクのため、既存のクラス属性に追加するタグの2番目の引数として)。
orokusaki

この質問は、この1のに関連すると思わstackoverflow.com/a/9801473/5739875
エフゲニーBobkin

多分このグリッドが役立つ:djangopackages.org/grids/g/navigation
guettli

回答:


74

テンプレートの継承を使用してナビゲーションをカスタマイズします。例えば:

base.html

<html>
    <head>...</head>
    <body>
        ...
        {% block nav %}
        <ul id="nav">
            <li>{% block nav-home %}<a href="{% url home %}">Home</a>{% endblock %}</li>
            <li>{% block nav-about %}<a href="{% url about %}">About</a>{% endblock %}</li>
            <li>{% block nav-contact %}<a href="{% url contact %}">Contact</a>{% endblock %}</li>
        </ul>
        {% endblock %}
        ...
    </body>
</html>

about.html

{% extends "base.html" %}

{% block nav-about %}<strong class="nav-active">About</strong>{% endblock %}

このアイデアは、特に柔軟性の点でとても気に入っていますが、DRYのトレードオフが少なくなります。私はサイトでこれを使い始めました。
匿名の臆病者、

22
同じサブテンプレートで複数のサイトセクションを処理することは珍しいことではないため、このアプローチには熱心ではありません。したがって、ビューにカスタム変数を配置し、テンプレートに条件を設定するか、サブテンプレートを再配置して、すべてが一意になるようにします。すべて、現在のサイトセクションを検出するためだけです。テンプレートタグアプローチは、最終的にはよりクリーンになります。
シャッカー2010

私は他のいくつかの解決策を見ました、そしてそれらはすべて少しハックのようです。これは少なくとも、実装/スクラップが非常に簡単でシンプルです。
mlissner

<ul id="nav">....</ul>別のファイルにリファクタリングしました。tabs.htmlとしましょう。そのため、base.htmlが含まれ{%block nav%}{%include "tabs.html"%}{%endblock%}、アクティブなタブの強調表示が機能しなくなりました(上記のabout.html内)。何か不足していますか?
なし。

@マディあなたは私が頭の中でそれをまっすぐに維持していることを私が絶対に確信しているわけではないという十分な間接性を持っていますが、答えはincludeタグがどのように機能するかに関係していると思います。ドキュメントに含まれているメモを確認してください:docs.djangoproject.com/en/dev/ref/templates/builtins/#includeあなたのケースでは、でベーステンプレートをオーバーライドしようとしてabout.htmlいるときまでに、処理されるのを待っているDjangoテンプレートブロックではなく、すでにレンダリングされたHTMLブロックを取得しています。
jpwatts

117

これを行うためにifは必要ありません。次のコードを見てください。

tags.py

@register.simple_tag
def active(request, pattern):
    import re
    if re.search(pattern, request.path):
        return 'active'
    return ''

urls.py

urlpatterns += patterns('',
    (r'/$', view_home_method, 'home_url_name'),
    (r'/services/$', view_services_method, 'services_url_name'),
    (r'/contact/$', view_contact_method, 'contact_url_name'),
)

base.html

{% load tags %}

{% url 'home_url_name' as home %}
{% url 'services_url_name' as services %}
{% url 'contact_url_name' as contact %}

<div id="navigation">
    <a class="{% active request home %}" href="{{ home }}">Home</a>
    <a class="{% active request services %}" href="{{ services }}">Services</a>
    <a class="{% active request contact %}" href="{{ contact }}">Contact</a>
</div>

それでおしまい。実装の詳細については、こちらをご覧ください:
gnuvince.wordpress.com
110j.wordpress.com


2
hrefのプロパティには、djangoテンプレートブラケット{{、}}がありません。たとえば、<a class="{% active request home %}" href="home"> Home </a>は、<a class = "{%active request home%}" href = "{{home}である必要があります} ">ホーム</a> tags.pyファイルにもいくつかのインクルードが必要です。そうでなければ、素晴らしい解決策です!
bsk

2
+1これは、アプリケーションとより疎結合です。私がタグを理解した初心者はそれが独自のアプリを必要としているので、それをグローバルなtags.pyファイルに単にダンプすることはできません。私はタグと呼ばれる新しいアプリを作成し、すべてが順調に進みました。docs.djangoproject.com/en/dev/howto/custom-template-tags
Keyo

3
@Keyo、プロジェクトにtemplatetagsディレクトリを作成し、プロジェクトをinstalledappsに追加します。それもトリックを行います。または、あなたが言ったように、プロジェクト内でアプリとしてメインサイトを作成します。
Josh Smeaton

5
追加することを忘れないでくださいdjango.core.context_processors.request、あなたにTEMPLATE_CONTEXT_PROCESSORSsettings.py
amigcamel

1
これは、ネストされた状態mysite.com(たとえば、ホームとして)とに対しては無効です。これはmysite.com/blog、パスが表示され//blog/(それぞれ)前者との一致が毎回発生するためです。/ランディングとして使用しない場合は、大丈夫かもしれませんが、それ以外の場合は単に使用しますreturn 'active' if pattern == request.path else ''(これに関する問題はまだ見たことがありませんが、これを使用して設定しただけです)。
nerdwaller 2015年

33

私は上記の110jのクリーン度が好きだったので、そのほとんどを取り、リファクタリングして、3つの問題を解決しました。

  1. 正規表現は「ホーム」URLを他のすべてのURLと照合していました
  2. 1つのナビゲーションタブに複数のURLをマッピングする必要があった私はパラメータの変化量をとり、より複雑なタグを必要に応じて、
  3. いくつかのURLの問題を修正

ここにあります:

tags.py:

from django import template

register = template.Library()

@register.tag
def active(parser, token):
    args = token.split_contents()
    template_tag = args[0]
    if len(args) < 2:
        raise template.TemplateSyntaxError, "%r tag requires at least one argument" % template_tag
    return NavSelectedNode(args[1:])

class NavSelectedNode(template.Node):
    def __init__(self, patterns):
        self.patterns = patterns
    def render(self, context):
        path = context['request'].path
        for p in self.patterns:
            pValue = template.Variable(p).resolve(context)
            if path == pValue:
                return "active" # change this if needed for other bootstrap version (compatible with 3.2)
        return ""

urls.py:

urlpatterns += patterns('',
    url(r'/$', view_home_method, {}, name='home_url_name'),
    url(r'/services/$', view_services_method, {}, name='services_url_name'),
    url(r'/contact/$', view_contact_method, {}, name='contact_url_name'),
    url(r'/contact/$', view_contact2_method, {}, name='contact2_url_name'),
)

base.html:

{% load tags %}

{% url home_url_name as home %}
{% url services_url_name as services %}
{% url contact_url_name as contact %}
{% url contact2_url_name as contact2 %}

<div id="navigation">
    <a class="{% active request home %}" href="home">Home</a>
    <a class="{% active request services %}" href="services">Services</a>
    <a class="{% active request contact contact2 %}" href="contact">Contact</a>
</div>

それはおそらくマーカス1で答えるのが一番ですが、「家」でどのように機能するのでしょうか それは常にアクティブですか?ルートURL呼び出し(www.toto.com/およびwww.toto.com/index)でのみアクティブにする方法は?どちらの回答でもこの問題は発生しません...
DestyNova

20

私はdjango-lineageの作者ですこの質問を解決するために特別に書いた:D

私は自分のプロジェクトで(完全に受け入れられる)jpwattsメソッドを使用してイライラし、110jの答えからインスピレーションを得ました。系統は次のようになります。

{% load lineage %}
<div id="navigation">
    <a class="{% ancestor '/home/' %}" href="/home/">Home</a>
    <a class="{% ancestor '/services/' %}" href="/services/">Services</a>
    <a class="{% ancestor '/contact/' %}" href="/contact/">Contact</a>
</div>

ancestor 引数が現在のページのURLの先頭と一致する場合は、単に「アクティブ」に置き換えられます。

可変引数、および完全な{% url %}型の逆解決もサポートされています。私はいくつかの構成オプションをちりばめ、少し具体化し、誰もが使えるようにパッケージ化しました。

誰かが興味を持っているなら、それについてもう少し読んでください:

>> github.com/marcuswhybrow/django-lineage


1
テンプレートへのハードコーディングパス:(
CpILL

10

Django 1.5以降:

すべての一般的なクラスベースのビュー(またはContextMixinから継承するクラスベースのビュー)では、コンテキストディクショナリにはViewインスタンスを指すビュー変数が含まれています。

そのため、このようなビューを使用している場合はbreadcrumbs、クラスレベルのフィールドとして何かいいものを追加して、それをテンプレートで使用できます。

ビューコードの例:

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

テンプレートでは、次のように使用できます。

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

親ナビゲーション項目をさらに「強調表示」する場合は、breadcrumbsリストを拡張する必要があります。

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

...そしてあなたのテンプレートで:

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

これは簡単でクリーンなソリューションであり、ネストされたナビゲーションで非常にうまく機能します。


その例では、3つのナビゲーション項目はすべてではありません.activeか?
Oli

はい。ただし、これは通常、マルチレベルナビゲーションで実現したいことです。もちろんbreadcrumbs、必要に応じて1つのアイテムを入れることもできます。しかし、あなたは正しい-私の例は最高のものではありません。
KonradHałas2013

@Oliの改善例。
KonradHałas2013

9

特定のナビゲーションアイテムではなく、ページのbody要素にクラスまたはIDを適用できます。

HTML:

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

CSS:

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

8

私はそれをこのようにします:

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

そして、私がしなければならないすべては私のビューで{'active_tab': 'statistics'}私のコンテキスト辞書に追加することです。

使用しているRequestContext場合は、テンプレートの現在のパスを次のように取得できます。

{{ request.path }}

そしてあなたの見解では:

from django.template import RequestContext

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

この情報を共有していただきありがとうございます。私はこの方法を使用しましたが、ナビゲーションバーにフラットページがあったため、それを検出して正しく強調表示するために、{%ifequal flatpage.url '/ about /'%}を使用しました。URLのハードコードされた検出は好きではありませんが、1回限りのハッキングで機能します。
Matt Garrison、

このソリューションの問題は、「統計」をコードにハードコーディングしたことです。これは、urlタグを使用してページのURLを取得する目的を無効にします。
2010年

7

私は上記のnivhabからコードを取り、いくつかの奇妙さを取り除き、きれいなテンプレートタグにして、/ account / edit /が引き続き/ account /タブをアクティブにするように修正しました。

#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

これは、上記のTobaによって提案されたcssソリューションの変形です。

基本テンプレートに以下を含めます。

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

次に、基本的な使用を拡張するテンプレートで:

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

次に、cssを使用して、bodyタグに基づいて現在の領域を強調表示できます(たとえば、nav-homeのIDを持つリンクがある場合)。

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


3

これまでの回答に感謝します。もう少し違うものを探しに行きました。

私のテンプレートでは:

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

ロジック(通常はurls.py)で表示しているページをclass="selected"特定したら、適切な名前でコンテキストの一部としてテンプレートに渡し ます。

たとえば、link1ページにいる場合は、追加します {'link1_active':' class="selected"'}にいる場合は、テンプレートのコンテキストにして、スクープして挿入します。

それは動作するように見え、それはかなりきれいです。

編集:コントローラー/ビューからHTMLを除外するために、これを少し変更しました:

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

テンプレートは少し読みにくくなりますが、私は同意します、urlsファイルから生のHTMLをプッシュしない方が良いです。


2
ビューで生のHTMLを処理することは、実際には避けてください。これは、この手法に必要なことです。カスタムテンプレートタグを書くことを考えましたか?
Justin Voss

あなたが正しい。HTMLの通過を停止するように編集しました。今はTrueを通過するだけです。私はまだテンプレートタグを書いていませんが、はい、これは始めるのに良い場所かもしれません。
Oli

2

ループを通じて動的に作成される同じページに複数のメニューがあります。コンテキストに関連する上記の投稿は私に迅速な修正を与えました。これが誰かを助けることを願っています。(私はアクティブなテンプレートタグに加えてこれを使用します-私の修正は動的な問題を解決します)。ばかげた比較のように見えますが、機能します。私は変数にactive_something-uniqueとsomething-uniqueという名前を付けました。これにより、ネストされたメニューで機能します。

これはビューの一部です(私が何をしているかを理解するのに十分です):

def project_list(request, catslug):
    "render the category detail page"
    category = get_object_or_404(Category, slug=catslug, site__id__exact=settings.SITE_ID)
    context = {
        'active_category': 
            category,
        'category': 
            category,
        'category_list': 
            Category.objects.filter(site__id__exact=settings.SITE_ID),

    }

そして、これはテンプレートからです:

<ul>
  {% for category in category_list %}
    <li class="tab{% ifequal active_category category %}-active{% endifequal %}">
      <a href="{{ category.get_absolute_url }}">{{ category.cat }}</a>
    </li>
  {% endfor %}
</ul>

2

私の解決策は、リクエストパスに基づいて変数を設定する単純なコンテキストプロセッサを記述することでした。

def navigation(request):
"""
Custom context processor to set the navigation menu pointer.
"""
nav_pointer = ''
if request.path == '/':
    nav_pointer = 'main'
elif request.path.startswith('/services/'):
    nav_pointer = 'services'
elif request.path.startswith('/other_stuff/'):
    nav_pointer = 'other_stuff'
return {'nav_pointer': nav_pointer}

(settings.pyのTEMPLATE_CONTEXT_PROCESSORSにカスタムプロセッサを追加することを忘れないでください。)

次に、ベーステンプレートで、リンクごとにifequalタグを使用して、「アクティブ」クラスを追加するかどうかを決定します。このアプローチがパス構造の柔軟性に厳密に制限されていることは確かですが、それは私の比較的控えめな展開で機能します。


私はそれが本当にあなたがさまざまな方法でサイトのセクションでは、(例えば、別のサイトのセクションごとに異なるテンプレートを使用して参照できるように、グローバルな文脈でこれらを持っていることは理にかなって考える1。。
shacker

2

私はnivhabの投稿に対するマイナーな機能強化を共有したかっただけです。私のアプリケーションでは、サブナビゲーションがあり、CSSだけを使用してそれらを非表示にしたくなかったため、アイテムのサブナビゲーションを表示するかどうかに関係なく、何らかの「if」タグが必要でした。

from django import template
register = template.Library()

@register.tag
def ifnaviactive(parser, token):
    nodelist = parser.parse(('endifnaviactive',))
    parser.delete_first_token()

    import re
    args = token.split_contents()
    template_tag = args[0]
    if len(args) < 2:
        raise template.TemplateSyntaxError, "%r tag requires at least one argument" % template_tag
    return NavSelectedNode(args[1:], nodelist)

class NavSelectedNode(template.Node):
    def __init__(self, patterns, nodelist):
        self.patterns = patterns
        self.nodelist = nodelist

    def render(self, context):
        path = context['request'].path
        for p in self.patterns:
            pValue = template.Variable(p).resolve(context)
            if path == pValue:
                return self.nodelist.render(context)
        return ""

これは、基本的にアクティブタグと同じ方法で使用できます。

{% url product_url as product %}

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

2

元のソリューションのもう1つの改良点です。

これは複数のパターンを受け入れます。これは、次のように、「」で囲まれた相対URLとして記述された名前のないパターンも最適です。

{% url admin:clients_client_changelist as clients %}
{% url admin:clients_town_changelist as towns %}
{% url admin:clients_district_changelist as districts %}

<li class="{% active "/" %}"><a href="/">Home</a></li>
<li class="{% active clients %}"><a href="{{ clients }}">Clients</a></li>
{% if request.user.is_superuser %}
<li class="{% active towns districts %}">
    <a href="#">Settings</a>
    <ul>
        <li><a href="{{ towns }}">Towns</a></li>
        <li><a href="{{ districts }}">Districts</a></li>
    </ul>
</li>
{% endif %}

タグは次のようになります:

from django import template

register = template.Library()

@register.tag
def active(parser, token):
    args = token.split_contents()
    template_tag = args[0]
    if len(args) < 2:
        raise template.TemplateSyntaxError, "%r tag requires at least one argument" % template_tag
    return NavSelectedNode(args[1:])

class NavSelectedNode(template.Node):
    def __init__(self, urls):
        self.urls = urls

    def render(self, context):
        path = context['request'].path

        for url in self.urls:
            if '"' not in url:
                cpath = template.Variable(url).resolve(context)
            else:
                cpath = url.strip('"')

            if (cpath == '/' or cpath == '') and not (path == '/' or path == ''):
                return ""
            if path.startswith(cpath):
                return 'active'
        return ""

2

jqueryを使用して、ナビゲーションバーを強調表示しました。このソリューションでは、CSSセレクターに適合する項目にCSSクラス「アクティブ」を追加するだけです。

<script type="text/javascript" src="/static/js/jquery.js"></script>
<script>
    $(document).ready(function(){
        var path = location.pathname;
        $('ul.navbar a.nav[href$="' + path + '"]').addClass("active");
    });
</script>

2

タグなしで@tbackの回答を少し強化%if%

# navigation.py
from django import template
from django.core.urlresolvers import resolve

register = template.Library()

@register.filter(name="activate_if_active", is_safe=True)
def activate_if_active(request, urlname):
  if resolve(request.get_full_path()).url_name == urlname:
    return "active"
  return ''

そのようなあなたのテンプレートでそれを使用してください:

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

そして"django.core.context_processors.request"、あなたのTEMPLATE_CONTEXT_PROCESSORS設定に含めてください。


2

最良の方法は、包含タグを使用することです。

templates/fnf/nav_item.html

<li class="nav-item">
    <a class="nav-link {% if is_active %}active{% endif %}" href="{% url url_name %}">{{ link_name }}</a>
</li>

これは、レンダリングする基本的なブートストラップナビゲーションアイテムです。

これは、href値、およびオプションでlink_name値を取得します。is_active現在のリクエストに基づいて計算されます。

templatetags/nav.py

from django import template

register = template.Library()


@register.inclusion_tag('fnf/nav_item.html', takes_context=True)
def nav_item(context, url_name, link_name=None):
    return {
        'url_name': url_name,
        'link_name': link_name or url_name.title(),
        'is_active': context.request.resolver_match.url_name == url_name,
    }

次に、それをナビゲーションで使用します。 templates/fnf/nav.html

{% load nav %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
        <ul class="navbar-nav mr-auto">
                {% nav_item 'dashboard' %}
            </ul>

おおざっぱな読み方ですが、これはURLの完全一致に限定されませんか?私は通常、このようなナビゲーションヒントをディープページにも使用します。あなたはどちらかにした場合についてNAVの項目がハイライト表示されます例えば/about/company-history/または /about/what-we-do/
オリ

1
はい。ただし、is_active置き換えることができ、辞書に追加された他のキーが返されます。また、小切手はcontext.request.resolver_match.url_name.startswith(x)他のものでもかまいません。また、dict値を確立するために、returnステートメントの前にコードを含めることができます。また、さまざまなテンプレートを使用することもできますtop_level_nav.html
たとえば

クリーンでシンプルなソリューション...いいね!
mmw

1

Andreasの回答を少し変更すると、urls.pyからテンプレートタグへのルートの名前を渡すことができるようです。私の例my_tasksでは、次にテンプレートタグ関数でreverse関数を使用して、URLがどうあるべきかを計算し、それをリクエストオブジェクト(テンプレートコンテキストで利用可能)のURLと照合できます。

from django import template
from django.core.urlresolvers import reverse

register = template.Library()

@register.tag
def active(parser, token):
    args = token.split_contents()
    template_tag = args[0]
    if len(args) < 2:
        raise template.TemplateSyntaxError, "%r tag requires at least one argument" % template_tag
    return NavSelectedNode(args[1:])

class NavSelectedNode(template.Node):
    def __init__(self, name):
        self.name = name

    def render(self, context):

        if context['request'].path == reverse(self.name[1]):
            return 'active'
        else:
            return ''

urls.py

url(r'^tasks/my', my_tasks, name = 'my_tasks' ),

template.html

<li class="{% active request all_tasks %}"><a href="{% url all_tasks %}">Everyone</a></li>

たぶん、もっと簡単なアプローチ:turnkeylinux.org/blog/django-navbar
jgsogo

1

私はパーティーに遅れていることを知っています。しかし、私は人気のあるソリューションのどれも好きではありませんでした:

ブロック法間違っているようだ:私は、ナビゲーションが自己が含まれるべきだと思います。

template_tag方法間違っているようだ:私はそのように私は、最初のURL、タグからURLを取得する必要はありません。また、css-classはタグではなくテンプレートで定義する必要があると思います。

したがって、私は上記で説明した欠点のないフィルターを作成しました。これはTrue、URLがアクティブである場合に返されるため、以下で使用できます{% if %}

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

コード:

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

RequestContextナビゲーションのあるページで使用するか、リクエストのcontext_processorを有効にしてくださいsettings.py

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

1

私が見てきたjpwatts '、110Jさん、nivhabさん&マーカスWhybrowの答えを、彼らはすべてのものに不足しているようだ:どのようなルートパスについて?なぜ常にアクティブなのですか?

だから私は別の方法をより簡単にしました。それは「コントローラー」がそれ自体で決定することを可能にし、そしてそれは大きな問題のほとんどを解決すると思います。

これが私のカスタムタグです:

## myapp_tags.py

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

次に、「コントローラー」が必要なCSSクラスを宣言します(実際、最も重要なのは、その存在をテンプレートに宣言することです)。

## views.py

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

そして最後に、ナビゲーションバーにレンダリングします。

<!-- sidebar.html -->

{% load myapp_tags %}
...

<a class="{% nav_css_class nav_home %}" href="{% url 'index' %}">
    Accueil
</a>
<a class="{% nav_css_class nav_candidats %}" href="{% url 'candidats' %}">
    Candidats
</a>
<a class="{% nav_css_class nav_ping %}" href="{% url 'ping' %}">
    Ping
</a>
<a class="{% nav_css_class nav_stat %}" href="{% url 'statistiques' %}">
    Statistiques
</a>
...

したがって、各ページにはnav_css_class設定する独自の値があり、設定されている場合、テンプレートはアクティブにレンダリングさrequestれます。テンプレートコンテキストでの必要はなく、URLパーシングは不要で、マルチURLページやルートページに関する問題は発生しません。


1

このソリューションに触発されて、私はこのアプローチを使い始めました:

**Placed in templates as base.html**

{% block tab_menu %}
<ul class="tab-menu">
  <li class="{% if active_tab == 'tab1' %} active{% endif %}"><a href="#">Tab 1</a></li>
  <li class="{% if active_tab == 'tab2' %} active{% endif %}"><a href="#">Tab 2</a></li>
  <li class="{% if active_tab == 'tab3' %} active{% endif %}"><a href="#">Tab 3</a></li>
</ul>
{% endblock tab_menu %}

**Placed in your page template**

{% extends "base.html" %}

{% block tab_menu %}
  {% with active_tab="tab1" %} {{ block.super }} {% endwith %}
{% endblock tab_menu %}

0

これが私の挑戦です。ナビゲーション構造(一部のメタデータを含むフラット)を含むクラスをビューに実装しました。次に、これをテンプレートに挿入してレンダリングします。

私のソリューションはi18nを扱います。もう少し抽象化する必要があるかもしれませんが、実際にはそれほど気にしていません。

views.py:

from django.utils.translation import get_language, ugettext as _


class Navi(list):
    items = (_('Events'), _('Users'), )

    def __init__(self, cur_path):
        lang = get_language()
        first_part = '/' + cur_path.lstrip('/').split('/')[0]

        def set_status(n):
            if n['url'] == first_part:
                n['status'] == 'active'

        for i in self.items:
            o = {'name': i, 'url': '/' + slugify(i)}
            set_status(o)
            self.append(o)

# remember to attach Navi() to your template context!
# ie. 'navi': Navi(request.path)

このようなincludeを使用してテンプレートロジックを定義しました。基本テンプレート:

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

実際のインクルード(includes / navigation.html):

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

うまくいけば、誰かがこれが役に立つと思うでしょう!ネストされた階層などをサポートするようにそのアイデアを拡張するのはかなり簡単だと思います。


0

インクルードテンプレート「intranet / nav_item.html」を作成します。

{% load url from future %}

{% url view as view_url %}
<li class="nav-item{% ifequal view_url request.path %} current{% endifequal %}">
    <a href="{{ view_url }}">{{ title }}</a>
</li>

そして、それをnav要素に含めます:

<ul>
    {% include "intranet/nav_item.html" with view='intranet.views.home' title='Home' %}
    {% include "intranet/nav_item.html" with view='crm.views.clients' title='Clients' %}
</ul>

そして、これを設定に追加する必要があります:

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

0

これはかなりシンプルなソリューションです、https://github.com/hellysmile/django-activeurl


1
回答の有用なポイントをここ、このサイトに投稿する必要があります。そうしないと、投稿が「回答なし」として削除されるリスクがあります。必要に応じてリンクを含めることもできますが、これは「参照」としてのみです。答えはリンクを必要とせず、それ自体で成り立つべきです。
Andrew Barber

0

このSO質問から

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

リンクごとに必要に応じて繰り返します。


これは直接一致する場合にのみ機能します。ほとんどのナビゲーションシステムは、子孫ページもアクティブである場合、ナビゲーションアイテムをアクティブとしてマークします。つまり/blog/posts/2021/04/12、/ blog / navアイテムがアクティブになるURLである場合。
Oli 2013年

@オリはい、それは時々動作しません。例えばstackoverflowのナビゲーションIEでQuestionsTagsUsersBadgesUnansweredAsk Question。では機能しませんQuestionsが、他のすべてのナビゲーションでは問題なく機能します。
suhailvs 2013年

0

また、jQueryを使用してそれを強調表示し、非セマンティックなDjangoテンプレートタグでテンプレートを乱雑にするよりもエレガントだと感じました。

以下のコードは、ブートストラップ3のネストされたドロップダウンで機能します(親<li>要素と子要素の両方を強調表示します)。

// DOM Ready
$(function() {
    // Highlight current page in nav bar
    $('.nav, .navbar-nav li').each(function() {
        // Count the number of links to the current page in the <li>
        var matched_links = $(this).find('a[href]').filter(function() {
            return $(this).attr('href') == window.location.pathname; 
        }).length;
        // If there's at least one, mark the <li> as active
        if (matched_links)
            $(this).addClass('active');
    });
});

また、template / htmlマークアップを変更せずに、現在のページのclickイベントを追加return false(またはhref属性をに変更#)するのも非常に簡単です。

        var matched_links = $(this).find('a[href]').filter(function() {
            var matched = $(this).attr('href') == window.location.pathname;
            if (matched)
                $(this).click(function() { return false; });
            return matched;
        }).length;

0

私はこのミックスインの組み合わせをクラスベースのビューに使用します:

class SetActiveViewMixin(object):
    def get_context_data(self, **kwargs):
        context = super(SetActiveViewMixin, self).get_context_data(**kwargs)
        context['active_nav_menu'] = {
            self.request.resolver_match.view_name: ' class="pure-menu-selected"'
        }
        return context

テンプレートでこれを使って:

<ul>
    <li{{active_nav_menu.node_explorer }}><a href="{% url 'node_explorer' '' %}">Explore</a></li>
    <li{{active_nav_menu.node_create }}><a href="{% url 'node_create' path %}">Create</a></li>
    <li{{active_nav_menu.node_edit }}><a href="{% url 'node_edit' path %}">Edit</a></li>
    <li{{active_nav_menu.node_delete }}><a href="{% url 'node_delete' path %}">Delete</a></li>
</ul>

0

私のものは以前に提出された別のJSアプローチに少し似ています... jQueryなしで...

base.htmlに次のようにあるとします。

<div class="pure-u-1 pure-menu pure-menu-open pure-menu-horizontal header" >
    <ul class="">
        <li id="home"><a href="{% url 'article:index' %}">Home</a></li>
        <li id="news"><a href="{% url 'article:index' %}">News</a></li>
        <li id="analysis"><a href="{% url 'article:index' %}">Analysis</a></li>
        <li id="opinion"><a href="{% url 'article:index' %}">Opinion</a></li>
        <li id="data"><a href="{% url 'article:index' %}">Data</a></li>
        <li id="events"><a href="{% url 'article:index' %}">Events</a></li>
        <li id="forum"><a href="{% url 'article:index' %}">Forum</a></li>
        <li id="subscribe"><a href="{% url 'article:index' %}">Subscribe</a></li>
    </ul>
    <script type="text/javascript">
        (function(){
            loc=/\w+/.exec(window.location.pathname)[0];
            el=document.getElementById(loc).className='pure-menu-selected';         
        })();   
    </script>
</div>

特定のURLパターンに従うように階層を作成しました...ホストアドレスの後に...ホーム、ニュース、分析などのメインカテゴリがあり、正規表現は最初の単語を場所から取り出します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.