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

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

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

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

6215閲覧

Django URL に親モデルのPK等と子モデルのPK等を表示したい

atsuton

総合スコア12

Django

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/02/10 18:15

■実現したいこと
Django にて文章を暗記するためのアプリを作ろうとしております。
URLに 親モデル(Book) の PK等、子モデル(Chapter) の PK等 を表示させるようにしたいです。

具体的には、
0. "path('book/chapter/int:pk/'" としている個所について、"path('book/bookのPK等を表示/chapter/int:pk/'" と表示させるようにしたい
例:book/1/chapter/1/
0. 1が実現できれば、"path('section/int:pk/'" も "book/1/chapter/1/section/1" といった形で表示させたいです。

そもそも実現可能か、url, view, テンプレートのどこを修正したらよいか、
アドバイスいただけますと助かります。

■試したこと①

urls.py 'book/chapter/<int:pk>/' ⇒ 'book/<int:bookid>/chapter/<int:pk>/' に変更 book_list.html <a href="{% url 'book_and_chapter_list' %}"> ⇒<a href="{% url 'book_and_chapter_list' pk=book.pk %}"> に変更

その結果、下記のように表示されました。

Reverse for 'book_and_chapter_list' with keyword arguments '{'pk': 1, 'bookid': 1}' not found. 1 pattern(s) tried: ['book/(?P<pk>[0-9]+)/$']

■試したこと②

urls.py 'book/<int:pk>/' ⇒ 'book/<int:pk>/<int:bookid>'

これで「試したこと①」のエラーは出なくなりました。
※エラーを出さないため、"int:bookid"を追記していますが、ここは'book/int:pk/'で動くようにしたいです。
そして別のエラーが表示されるようになりました。

book_and_chapter_list() got an unexpected keyword argument 'bookid'

■試したこと③

views.py def book_and_chapter_list(request, pk): book = get_object_or_404(Book, pk=pk) ⇒ def book_and_chapter_list(request, pk, bookid): book = get_object_or_404(Book, pk=pk, bookid=bookid)

結果は以下の通りでした。一旦ここであきらめて質問させていただいております。

Cannot resolve keyword 'bookid' into field. Choices are: book_title, chapter, id

■データの概要など
書籍名(Book)、その書籍の章(Chapter)、その書籍の節と内容(SectionAndContent)の3つのモデルに分けて、
Book を Chapter の親モデルに
Chapter を SectionAndContent の親モデルにしています。

画面は以下のようにしています。
●画面1

・書籍名1
・書籍名2

●画面2
・書籍名1
・章名1
・章名2
・章名3

●画面3
・書籍名1
・章名1
・内容

■環境
・python 3.7.1
・Django 2.0.9

■models.py

models

1 2from django.core.validators import MinValueValidator, MaxValueValidator 3from django.db import models 4 5 6class Book(models.Model): 7 book_title = models.CharField('タイトル', max_length=100) 8 def __str__(self): 9 return self.book_title 10 11 12class Chapter(models.Model): 13 book = models.ForeignKey(Book, on_delete=models.PROTECT) 14 chapter_number = models.IntegerField(verbose_name='章番号', validators=[MinValueValidator(1), MaxValueValidator(100)], unique=True) 15 chapter_title = models.CharField('タイトル', max_length=100) 16 def __str__(self): 17 return str(self.chapter_number) + ". " + self.chapter_title 18 19 class Meta: 20 unique_together = ('book', 'chapter_number') 21 22 23class SectionAndContent(models.Model): 24 RANK_CHOICES = (('A','A'),('B','B'),('C','C'),(' ',' ')) 25 chapter = models.ForeignKey(Chapter, on_delete=models.PROTECT, to_field="chapter_number") 26 section_number = models.IntegerField(verbose_name='節番号', validators=[MinValueValidator(1), MaxValueValidator(100)]) 27 section_title = models.CharField('タイトル', max_length=100) 28 display_order = models.IntegerField(verbose_name='表示順', validators=[MinValueValidator(1), MaxValueValidator(100)]) 29 rank = models.CharField(verbose_name='ランク', max_length=2, choices=RANK_CHOICES, default=' ') 30 content_text = models.TextField(verbose_name='', blank=True, null=True, max_length=5000) 31 32 def __str__(self): 33 return str(self.chapter.id) + "-" + str(self.section_number) + ". " + self.section_title 34 35 def my_function(self): 36 return str(self.content_text).splitlines() 37 38 class Meta: 39 unique_together = ('chapter', 'section_number')

■urls.py

urls

1from django.urls import path, include 2from . import views 3 4 5urlpatterns = [ 6 path('', views.book_list, name='book_list'), 7 path('book/<int:pk>/', views.book_and_chapter_list, name='book_and_chapter_list'), 8 path('book/chapter/<int:pk>/', views.chapter_and_section_list, name='chapter_and_section_list'), 9 path('section/<int:pk>/', views.section_and_content, name='section_and_content'), 10]

■views.py

views

1def book_list(request): 2 books = Book.objects.all() 3 return render(request, 'anki/book_list.html', {'books':books}) 4 5 6def book_and_chapter_list(request, pk): 7 book = get_object_or_404(Book, pk=pk) 8 return render(request, 'anki/book_and_chapter_list.html', {'book': book}) 9 10 11def chapter_and_section_list(request, pk): 12 chapter = get_object_or_404(Chapter, pk=pk) 13 return render(request, 'anki/chapter_and_section_list.html', {'chapter': chapter}) 14 15 16def section_and_content(request, pk): 17 section = get_object_or_404(SectionAndContent, pk=pk) 18 return render(request, 'anki/section_and_content.html', {'section': section})

■book_list.html

template

1{% extends 'anki/base.html' %} 2 3{% block content %} 4 {% for book in books %} 5 <div class="book-title"> 6 <h1><a href="{% url 'book_and_chapter_list' pk=book.pk %}">{{ book.book_title }}</a></h1> 7 </div> 8 {% endfor %} 9{% endblock %}

■book_and_chapter_list.html

template

1{% extends 'anki/base.html' %} 2 3{% block content %} 4 <div class="post"> 5 <div class="book-title"> 6 <h2>{{ book }}</h2> 7 </div> 8 {% for chapter in book.chapter_set.all %} 9 <div class="chapter-title"> 10 <h1><a href="{% url 'chapter_and_section_list' pk=chapter.pk %}">{{ chapter }}</a> 11 </div> 12 {% endfor %} 13 </div> 14{% endblock %}

■section_and_content.html

template

1{% extends 'anki/base.html' %} 2 3{% block content %} 4 <div class="title"> 5 {{ section.chapter_id}}-{{ section.section_number}}. {{section.section_title}} 6 </div> 7 <div class="content"> 8 {{ section.content_text | safe | linebreaksbr }} 9 </div> 10 <div> 11 {{ request.user }} 12 </div> 13 14{% endblock %} 15 16{% block extrajs %}{% endblock %}

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

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

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

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

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

guest

回答1

0

ベストアンサー

問題の文章をすべて読みきれていませんが(すみません)、ご要望は「関連する 2 つのモデルの pk が URL に含まれる形にしたい」とのことですね。

実現可能だと思います。例えば次のように書かれるとよいのではないでしょうか。

urls.py:

patch

1- path('book/chapter/<int:pk>/', views.chapter_and_section_list, name='chapter_and_section_list'), 2+ path('book/<int:book_pk>/chapter/<int:chapter_pk>/', views.chapter_and_section_list, name='chapter_and_section_list'),

views.py:

python

1def chapter_and_section_list(request, book_pk, chapter_pk): 2 book = get_object_or_404(Book, pk=book_pk) 3 chapter = get_object_or_404(Chapter, pk=chapter_pk, book=book) 4 return render(request, 'anki/chapter_and_section_list.html', {'chapter': chapter})

ことばで補足しなくてもコードをご覧いただけばアイデアは伝わるのではないかと思いますがいかがでしょうか。

Django では通常ルーティングと view のコードが別のファイルに分かれるため、複数のモデルが関係するところで単に pk とだけ書くとどのモデルの pk なのか混乱しやすくなるので、複数のモデルが関係するところでは xxx_pk と区別しやすい名前にする方がよいのかなと個人的には思います。

(上のコードは私の手元で動作確認をしていないので、そっくりそのまま採用するのではなくアイデアのみ参考にしてください)

(ここで問題に関係しているのはルーティングと view だけで、テンプレートは特に影響が無いのかなと思いましたので、テンプレートのコードは見せていただいていません。テンプレートは view の変更にあわせて必要に応じてよきようにご変更いただくだけで大丈夫かなと思います)

投稿2019/02/12 13:06

gh640

総合スコア1407

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

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

atsuton

2019/02/13 14:16

お忙しい中ご回答ありがとうございます。 試してみて、結果をお知らせいたします。 取り急ぎお礼まで。
atsuton

2019/02/13 14:29

gh640様 試してみたところ、期待通りにURLが表示されるようになりました。 ありがとうございました。大変助かりました!
gh640

2019/02/18 05:26

atsuton 様 せっかくコメントをいただいたのに反応が遅くなってしまい申し訳ありません。そうですか!ご丁寧に状況をご共有くださりありがとうございます。よかったです :D
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問