Djangoでbase.htmlにデータを渡す方法をご紹介します。
条件
- Django 2.1.3
- Python 3.7.0
実現する内容
Djangoでテンプレートを実装する際、ナビゲーションバーなど共通で使用するものは「base.html」として共通化して、各ページで{% extends ‘base.html’ %}してテンプレートを拡張する手段が用いられます。
https://tutorial.djangogirls.org/ja/template_extending/
ここでは、base.htmlに特定の情報を渡すことで、ページごとにナビゲーションバーの表示を切り替えてみたいと思います。
具体的には以下の通りです。
- 一覧画面では、ナビゲーションバーの特定リンクを表示しない。
- 詳細画面では、ナビゲーションバーの特定リンクを表示する。
実現方法
詳細画面のviewで「def get_context_data(self, **kwargs):」を定義することにより、テンプレートへデータを渡します。
https://docs.djangoproject.com/ja/2.1/ref/class-based-views/mixins-simple/#django.views.generic.base.ContextMixin.get_context_data
views.py
ここでは「my_model_pk」という変数を定義し、MyModelのpkを渡しています。
class IndexView(LoginRequiredMixin, generic.ListView):
ordering = ['-updated_at']
template_name = 'monitor/index.html'
class DetailView(LoginRequiredMixin, generic.DetailView):
template_name = 'monitor/detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['my_model_pk'] = self.kwargs['pk']
# 一覧画面
class IndexView(LoginRequiredMixin, generic.ListView):
model = MyModel
paginate_by = 5
ordering = ['-updated_at']
template_name = 'monitor/index.html'
# 詳細画面
class DetailView(LoginRequiredMixin, generic.DetailView):
model = MyModel
template_name = 'monitor/detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['my_model_pk'] = self.kwargs['pk']
return context
# 一覧画面
class IndexView(LoginRequiredMixin, generic.ListView):
model = MyModel
paginate_by = 5
ordering = ['-updated_at']
template_name = 'monitor/index.html'
# 詳細画面
class DetailView(LoginRequiredMixin, generic.DetailView):
model = MyModel
template_name = 'monitor/detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['my_model_pk'] = self.kwargs['pk']
return context
base.html
{% if my_model_pk %}{% endif %}によって、my_model_pkという変数が存在した場合のみ、ナビゲーションバーに「グラフ」というメニューが表示されるようになります。
すなわち、一覧画面では「グラフ」は表示されず、詳細画面では「グラフ」がナビゲーションバーに表示されます。
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="{% url 'monitor:index' %}">温室監視サービス</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
{% if user.is_authenticated %}
<a class="nav-link" href="{% url 'monitor:index' %}">TOP</a>
<a class="nav-link" href="{% url 'monitor:graph' my_model_pk %}">グラフ</a>
<a class="nav-link" href="{% url 'monitor:password_change' %}" class="logout">パスワード変更</a>
<a class="nav-link" href="{% url 'logout' %}">ログアウト</a>
<a class="nav-link" href="{% url 'monitor:password_reset' %}">パスワード忘れ</a>
<a class="nav-link" href="{% url 'monitor:index' %}" class="login">ログイン</a>
<!-- base.html抜粋 -->
<body>
<main>
<!-- ナビゲーションバーの設定 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container">
<a class="navbar-brand" href="{% url 'monitor:index' %}">温室監視サービス</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:index' %}">TOP</a>
</li>
{% if my_model_pk %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:graph' my_model_pk %}">グラフ</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:password_change' %}" class="logout">パスワード変更</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'logout' %}">ログアウト</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:password_reset' %}">パスワード忘れ</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:index' %}" class="login">ログイン</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
{% block content %}
{% endblock %}
</main>
</body>
<!-- base.html抜粋 -->
<body>
<main>
<!-- ナビゲーションバーの設定 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container">
<a class="navbar-brand" href="{% url 'monitor:index' %}">温室監視サービス</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:index' %}">TOP</a>
</li>
{% if my_model_pk %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:graph' my_model_pk %}">グラフ</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:password_change' %}" class="logout">パスワード変更</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'logout' %}">ログアウト</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:password_reset' %}">パスワード忘れ</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'monitor:index' %}" class="login">ログイン</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
{% block content %}
{% endblock %}
</main>
</body>
urls.py
グラフ描画画面は詳細画面ごとに存在するものとします。
(”monitor/<int:pk>/graph/”)
base.htmlにおいて、「href=”{% url ‘monitor:graph’ my_model_pk %}」のようにpkをパラメータとしてページへのリンクを張っています。
path('', views.IndexView.as_view(), name='index'),
path('monitor/<int:pk>/', views.DetailView.as_view(), name='detail'),
path("monitor/<int:pk>/graph/", views.GraphView.as_view(), name='graph'),
path('password_change/', views.PasswordChange.as_view(), name='password_change'),
path('password_change/done/', views.PasswordChangeDone.as_view(), name='password_change_done'),
path('password_reset/', views.PasswordReset.as_view(), name='password_reset'),
path('password_reset/done/', views.PasswordResetDone.as_view(), name='password_reset_done'),
path('reset/<uidb64>/<token>/', views.PasswordResetConfirm.as_view(), name='password_reset_confirm'),
path('reset/done/', views.PasswordChangeComplete.as_view(), name='password_reset_complete'),
# urls.py抜粋
urlpatterns = [
# トップ画面
path('', views.IndexView.as_view(), name='index'),
# 詳細画面
path('monitor/<int:pk>/', views.DetailView.as_view(), name='detail'),
# グラフ描画画面
path("monitor/<int:pk>/graph/", views.GraphView.as_view(), name='graph'),
# パスワード変更画面
path('password_change/', views.PasswordChange.as_view(), name='password_change'),
path('password_change/done/', views.PasswordChangeDone.as_view(), name='password_change_done'),
# パスワードリセット画面
path('password_reset/', views.PasswordReset.as_view(), name='password_reset'),
path('password_reset/done/', views.PasswordResetDone.as_view(), name='password_reset_done'),
path('reset/<uidb64>/<token>/', views.PasswordResetConfirm.as_view(), name='password_reset_confirm'),
path('reset/done/', views.PasswordChangeComplete.as_view(), name='password_reset_complete'),
]
# urls.py抜粋
urlpatterns = [
# トップ画面
path('', views.IndexView.as_view(), name='index'),
# 詳細画面
path('monitor/<int:pk>/', views.DetailView.as_view(), name='detail'),
# グラフ描画画面
path("monitor/<int:pk>/graph/", views.GraphView.as_view(), name='graph'),
# パスワード変更画面
path('password_change/', views.PasswordChange.as_view(), name='password_change'),
path('password_change/done/', views.PasswordChangeDone.as_view(), name='password_change_done'),
# パスワードリセット画面
path('password_reset/', views.PasswordReset.as_view(), name='password_reset'),
path('password_reset/done/', views.PasswordResetDone.as_view(), name='password_reset_done'),
path('reset/<uidb64>/<token>/', views.PasswordResetConfirm.as_view(), name='password_reset_confirm'),
path('reset/done/', views.PasswordChangeComplete.as_view(), name='password_reset_complete'),
]
動作確認
一覧画面
一覧画面では「グラフ」というメニューは表示されません。

詳細画面
詳細画面では「グラフ」というメニューが表示されます。


「グラフ」メニューにカーソルを持っていくと、各詳細画面のpk値に応じたリンクとなっていることがわかります。


以上で画面に応じたナビゲーションバーのメニュー切り替えサンプルは終わりです。
Django