質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

10410閲覧

(Django)同一テンプレート内にてURLの動的変更について

mickey

総合スコア27

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

2クリップ

投稿2017/04/07 13:18

###前提・実現したいこと
Python3.6.0でDjangoを用いてクラシファイドサイトの作成をしています。同一テンプレート内にてURLの動的変更についてわからないことがあるので教えてください。

まずはソースコード載せます。
###該当のソースコード

from django.db import models class Category(models.Model): parent = models.ForeignKey('Category', related_name='children', null=True, blank=True) name = models.CharField(max_length=255) slug = models.SlugField() @property def dispatch(self): # parent が nullであれば親カテゴリなので自分自身を返す if not self.parent: return self # そうでなければ親カテゴリ(parent)を返す else: return self.parent def __str__(self): return self.name class Location(models.Model): parent = models.ForeignKey('Location', related_name='children', null=True, blank=True) name = models.CharField(max_length=255) slug = models.SlugField() @property def dispatch(self): # parent が nullであればStateなので自分自身を返す if not self.parent: return self # そうでなければState(parent)を返す else: return self.parent def __str__(self): return self.name class PostQuerySet(models.QuerySet): def filter_category(self, category): if not category.parent: # Big Category であれば、childrenのカテゴリに所属するPostをfilter return self.filter(category__in=category.children.all()) else: # Small Category であれば、categoryに所属するPostをfilter return self.filter(category=category) def filter_location(self, location): if not location.parent: # State であれば、childrenのlocationに所属するPostをfilter return self.filter(location__in=location.children.all()) else: # Region であれば そのlocationに所属するPostをfilter return self.filter(location=location) class Post(models.Model): category = models.ForeignKey(Category) location = models.ForeignKey(Location) title = models.CharField(max_length=255) text = models.CharField(max_length=255) objects = PostQuerySet.as_manager() def __str__(self): return self.title urlpatterns = [ url(r'^all-categories/$', views.all_cat_index, name='index'), url(r'^all-categories/(?P<loc>[-\w]+)/$', views.all_cat_loc_index, name='index'), url(r'^(?P<cat>[-\w]+)/$', views.cat_index, name='index'), url(r'^(?P<cat>[-\w]+)/(?P<loc>[-\w]+)/$', views.cat_loc_index, name='index'), ] def all_cat_index(request): big_cats = Category.objects.filter(parent__isnull=True) states = Location.objects.filter(parent__isnull=True) c = { 'big_cats': big_cats, 'states': states, 'posts': Post.objects.all() } return render(request, 'classifieds/index.html', c) def all_cat_loc_index(request, loc): location = get_object_or_404(Location, slug=loc) c = { 'big_cats': Category.objects.filter(parent__isnull=True), 'state': location.dispatch, 'posts': Post.objects.filter_location(location).all() } return render(request, 'classifieds/index.html', c) def cat_index(request, cat): category = get_object_or_404(Category, slug=cat) c = { 'big_cat': category.dispatch, 'states': Location.objects.filter(parent__isnull=True).all(), 'posts': Post.objects.filter_category(category).all() } return render(request, 'classifieds/index.html', c) def cat_loc_index(request, cat, loc): category = get_object_or_404(Category, slug=cat) location = get_object_or_404(Location, slug=loc) c = { 'big_cat': category.dispatch, 'state': location.dispatch, 'posts': Post.objects.filter_category(category).filter_location(location).all() } return render(request, 'classifieds/index.html', c) {% extends 'base.html' %} {% block left %} <p>[カテゴリー]</p> <ul> {% if big_cat %} <li><a href="{% url 'classifieds:index' param %}">{{ big_cat.name }}</a></li> {% for small_cat in big_cat.children.all %} <li><a href="{% url 'classifieds:index' param %}">{{ small_cat.name }}</a></li> {% endfor %} {% else %} {% for big_cat in big_cats %} <li><a href="{% url 'classifieds:index' param %}">{{ big_cat.name }}</a></li> {% endfor %} {% endif %} </ul> <p>[フィルター]</p> <ul> {% if state %} <li><a href="{% url 'classifieds:index' param %}">{{ state.name }}</a></li> {% for region in state.children.all %} <li><a href="{% url 'classifieds:index' param %}">{{ region.name }}</a></li> {% endfor %} {% else %} {% for state in states %} <li><a href="{% url 'classifieds:index' param %}">{{ state.name }}</a></li> {% endfor %} {% endif %} </ul> {% endblock %} {% block content %} <ul> {% for post in posts %} <li>{{ post.title }} | {{ post.category }} | {{ post.location }}</li> {% endfor %} </ul> {% endblock %}

<a href="{% url 'index' big_cat.slug %}">{{ big_cat.name }}</a>をクリックして遷移するページは/category/で、このときにこのリンクを<a href="{% url 'index' big_cat.slug state.slug %}">というように、big_cat.slugがすでに含まれている状態に動的に変化させたいです。

categoryをクリックして遷移した先のページURLは/category/だとします。この状態でlocationをクリックしてURLを/category/location/としたい場合、こういった動的なURLの生成を実現するためにはどうすればいいのでしょうか?

kino0120👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

テンプレート中の {% url %} テンプレートタグのパラメータがすべて param とプレースホルダのような書き方になっておりますが、このあたり (テンプレートの書き方) でお悩みということで良いでしょうか。特に Location へのフィルターリンクを作る部分に、 Category 選択の有無によって違う URL を出力させたいということですよね。

以下、実際に mickey さんがどうしたいかによって答えが変わり得ると思いましたので、いくつか選択肢を提示させて頂きました。根本的に質問をとらえ違えていたらすみません。

方法 1 - 愚直に条件分岐させる

残念ながら Django のテンプレートエンジンはあまりトリッキーなことはできない (ようにすることで、分かりやすさを維持している) ため、愚直に条件分岐をしていくしか無いように思います。具体的には、次のようなちょっと冗長なコードになってしまいます。

html

1<p>[フィルター]</p> 2<ul> 3 {% if state %} 4 {% if big_cat %} 5 <li><a href="{% url 'classifieds:index' cat=big_cat.slug loc=state.slug %}">{{ state.name }}</a></li> 6 {% else %} 7 <li><a href="{% url 'classifieds:index' loc=state.slug %}">{{ state.name }}</a></li> 8 {% endif %} 9 {% for region in state.children.all %} 10 {% if big_cat %} 11 <li><a href="{% url 'classifieds:index' cat=big_cat.slug loc=region.slug %}">{{ region.name }}</a></li> 12 {% else %} 13 <li><a href="{% url 'classifieds:index' loc=region.slug %}">{{ region.name }}</a></li> 14 {% endif %} 15 {% endfor %} 16 {% else %} 17 {% for state in states %} 18 {% if big_cat %} 19 <li><a href="{% url 'classifieds:index' cat=big_cat.slug loc=state.slug %}">{{ state.name }}</a></li> 20 {% else %} 21 <li><a href="{% url 'classifieds:index' loc=state.slug %}">{{ state.name }}</a></li> 22 {% endif %} 23 {% endfor %} 24 {% endif %} 25</ul>

ただ、あんまりにも冗長なのは確かなので、もう少し見通しをよくする手段としては、一つは別のテンプレートに切り出して {% include %} するという方法があると思います。次のように、リンク部分だけのテンプレートを作っておく方法です。

html

1{# classifieds/_filter_link.html を作成 #} 2{% if big_cat %} 3 <li><a href="{% url 'classifieds:index' cat=big_cat.slug loc=location.slug %}">{{ location.name }}</a></li> 4{% else %} 5 <li><a href="{% url 'classifieds:index' loc=location.slug %}">{{ location.name }}</a></li> 6{% endif %} 7 8{# classifieds/index.html からの呼び出し #} 9<p>[フィルター]</p> 10<ul> 11 {% if state %} 12 {% include 'classifieds/_filter_link.html' with location=state %} 13 {% for region in state.children.all %} 14 {% include 'classifieds/_filter_link.html' with location=region %} 15 {% endfor %} 16 {% else %} 17 {% for state in states %} 18 {% include 'classifieds/_filter_link.html' with location=state %} 19 {% endfor %} 20 {% endif %} 21</ul>

方法 2 - URL 設計の仕様を使う

他には、今回の URL の設計を前提にする限り、 "all-categories" という slug を「カテゴリ未選択」の slug だと見做すことができますから、これを使って常にビューから slug を与えてやるのも良いかもしれません。

つまり、 big_cat を持つ場合は 'category_slug': big_cat.slug を、持たない場合は 'category_slug': 'all-categories'c 変数に入れて渡してやることにし、テンプレートでは条件分岐せずに次のように書きます。

html

1<li><a href="{% url 'classifieds:index' cat=category_slug loc=location.slug %}">{{ location.name }}</a></li>

このようにすれば、 big_cat を持たない場合、本来 Category の slug が入るところに "all-categories" が入ってくれるため、結果的に想定通りの動作をしてくれることになります。ただ、この先もし URL をちょっといじくりたい、と思ったときに、ビューまで書き換えなければならなくなるのが難点です。

方法 3 - 絞り込みはクエリで行う

あとは、さらに URL の設計が mickey さんの想定と異なるものになってしまうかもしれませんが、フィルタリングの条件は URL のパスに含むのでなく、クエリに含めてしまうというのも一つの解決方法かもしれません。つまり、 /category/location/Location 絞り込みを行うのではなく /category/?location=locationLocation 絞り込みを行うという方法です。テンプレート上は、次のような書き方になります。

html

1<li><a href="?location={{ location.slug }}">{{ location.name }}</a></li>

この方法であれば、ブラウザが「現在の URL」に対してクエリを付与してくれるので、現在どのようなカテゴリが選択されているかを気にすることなく動作してくれます。Django の URL 解決の仕様に煩わされることもありません。

投稿2017/04/08 15:56

argparse

総合スコア1017

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問