データベースのMemoテーブル(「プロジェクト構成・ファイル」のmodels.py参照)の一覧表示,タプルの新規作成ができるwebアプリケーションを実装しました.そしてそのテーブルの属性の1つに,ManyToManyFieldでTagテーブルを指定し,実装しました.以下のふたつの疑問を解消したいです.
(疑問①)Memoテーブルの一覧表示にそれぞれのタグを表示するにはどのように実装すれば良いか.
(疑問②)Memoテーブルに指定したMemoCreateViewで,Tagテーブルのタプルを新規作成するフォームをどのように実装すれば良いか.(MemoCreateViewでの実装は一般的ではないのか)
webアプリケーション初心者です.認識なども間違っている点があると思うのでご指摘いただきたいです.
プロジェクト構成・ファイル
console
1$ tree django_test_project1 2django_test_project1 3├── config 4│ ├── __init__.py 5│ ├── settings.py 6│ ├── urls.py 7│ └── wsgi.py 8├── db.sqlite3 9├── manage.py 10└── memo 11 ├── __init__.py 12 ├── admin.py 13 ├── apps.py 14 ├── forms.py 15 ├── migrations 16 │ ├── 0001_initial.py 17 │ ├── 0002_memo_created_at.py 18 │ └── __init__.py 19 ├── models.py 20 ├── templates 21 │ ├── memo_create.html 22 │ └── memo_list.html 23 ├── tests.py 24 ├── urls.py 25 └── views.py 26 274 directories, 19 files
python
1# memo/models.py 2 3from django.db import models 4 5class Tag(models.Model): 6 name = models.CharField( 7 verbose_name='タグ名', 8 max_length=127, 9 ) 10 def __str__(self): 11 return self.name 12 13class Memo(models.Model): 14 title = models.CharField( 15 verbose_name='タイトル', 16 max_length=255, 17 ) 18 content = models.TextField( 19 verbose_name='本文', 20 blank=True, 21 null=True, 22 ) 23 tags = models.ManyToManyField( 24 Tag, 25 verbose_name='タグ', 26 blank=True, 27 ) 28 created_at = models.DateTimeField( 29 verbose_name='作成日時', 30 auto_now=True, 31 ) 32 33 def __str__(self): 34 return self.title 35
python
1# memo/urls.py 2 3from django.urls import path 4from . import views 5 6app_name = 'memo' 7urlpatterns = [ 8 path('', views.MemoListView.as_view(), name='memo_list'), 9 path('memo_create/', views.MemoCreateView.as_view(), name='memo_create'), 10] 11
python
1# memo/views.py 2 3from django.views.generic import ListView 4from django.views.generic import CreateView 5from django.urls import reverse_lazy 6 7from .models import Memo 8from .forms import MemoCreateForm 9 10class MemoListView(ListView): 11 model = Memo 12 template_name = 'memo_list.html' 13 14 def get_queryset(self): 15 memo_list = Memo.objects.all().order_by('-created_at') 16 return memo_list 17 18class MemoCreateView(CreateView): 19 model = Memo 20 template_name = 'memo_create.html' 21 form_class = MemoCreateForm 22 success_url = reverse_lazy('memo:memo_list') 23
python
1# memo/forms.py 2 3from django.forms import ModelForm 4from .models import Memo 5 6class MemoCreateForm(ModelForm): 7 class Meta: 8 model = Memo 9 fields = ('title', 'content', 'tags') 10
html
1<!-- memo/templates/memo_list.html --> 2 3<!DOCTYPE html> 4<html lang="ja"> 5<head> 6 <meta charset="UTF-8"> 7 <title>Memo List</title> 8</head> 9<body> 10<a href="{% url 'memo:memo_create' %}">新規メモ作成</a> 11<table border="2"> 12 <thead> 13 <tr> 14 <th>タイトル</th> 15 <th>内容</th> 16 <th>タグ</th> 17 </tr> 18 </thead> 19 <tbody> 20 {% for memo in memo_list %} 21 <tr> 22 <td>{{ memo.title }}</td><td>{{ memo.content }}</td><td>{{ memo.tags }}</td> 23 <!-- 上記だとmemo.tagsはmemo.Tag.Noneと表示されてしまいます. --> 24 </tr> 25 {% endfor %} 26 </tbody> 27</table> 28</body> 29</html> 30
html
1<!-- memo/templates/memo_create.html --> 2 3<!DOCTYPE html> 4<html lang="ja"> 5<head> 6 <meta charset="UTF-8"> 7 <title>Memo Create</title> 8</head> 9<body> 10<form method="post"> 11 <table> 12 {% csrf_token %} 13 {{ form.as_table }} 14 </table> 15 <button type="submit">作成</button> 16</form> 17</body> 18</html> 19
疑問①に関した試したこと
- memo.tagsをforタグでまわす
memo_list.htmlのなかでmemo.tagsをforタグでまわそうとしたところ,ブラウサにDjangoのエラーが出力されてしまいました.エラーによると「memo.tagsはManyRelatedMnager objectであり,iterableではない」とのことなのですが,ManyRelatedManagerとはなんなのでしょうか.
html
1# memo_list.html 2 3<!-- 略 --> 4 5 <tbody> 6 {% for memo in memo_list %} 7 <tr> 8 <td>{{ memo.title }}</td><td>{{ memo.content }}</td> 9 <td> 10 {% for tag in memo.tags %} 11 {{ tag.name }} 12 {% endfor %} 13 </td> 14 </tr> 15 {% endfor %} 16 </tbody> 17 18<!-- 略 --> 19
browser
1# エラー 2TypeError at / 3'ManyRelatedManager' object is not iterable 4 5Request Method: GET 6Request URL: http://127.0.0.1:8000/ 7Django Version: 2.2.5 8Exception Type: TypeError 9Exception Value: 'ManyRelatedManager' object is not iterable
- get_querysetメソッドでタグをわたす
MemoListViewクラスのget_querysetメソッドの中でmemoオブジェクトにmemo.tag_listという属性を追加したところ,表示できました.この実装は最も良い方法なのでしょうか.また,select_relatedメソッドはDBの読み込み回数を省略できるとのことだったので,後ろに付けたのですが,使い方は正しいのでしょうか.
python
1# views.py 2 3# 略 4 5class MemoListView(ListView): 6 model = Memo 7 template_name = 'memo_list.html' 8 9 def get_queryset(self): 10 memo_list = Memo.objects.all().order_by('-created_at') 11 for memo in memo_list: 12 memo.tag_list = memo.tags.all().select_related() 13 return memo_list 14 15# 略 16
html
1# memo_list.html 2 3<!-- 略 --> 4 5 <tbody> 6 {% for memo in memo_list %} 7 <tr> 8 <td>{{ memo.title }}</td><td>{{ memo.content }}</td> 9 <td> 10 {% for tag in memo.tag_list %} 11 「{{ tag.name }}」 12 {% endfor %} 13 </td> 14 </tr> 15 {% endfor %} 16 </tbody> 17 18<!-- 略 --> 19
疑問②に関して試したこと
django.views.generic.CreateViewを継承したViewClassでのタグの新規作成フォームの作成方法はわかりませんでした.django.views.generic.Viewを継承したクラスを用いて,自分でformをテンプレートに記述してみましたが,Memoテーブルのタプルの新規作成用のformタグの中で,Tagテーブルのタプルの新規作成用のフォームタグを実装する方法がわかりませんでした.調べたところformタグのネストはできないようです.このような状況の場合の良い実装方法を教えてください.別々に記述するしかないのでしょうか.
python
1# views.py 2 3# 略 4 5class MemoCreateView(View): 6 7 def get(self, request, *args, **kwargs): 8 tag_list = Tag.objects.all() 9 context = { 10 'tag_list': tag_list, 11 } 12 return render(request, 'memo_create.html', context) 13 14 def post(self, request, *args, **kwargs): 15 if request.POST["title"] != "": 16 memo = Memo(title=request.POST['title'], content=request.POST['content']) 17 memo.save() 18 for tag in request.POST.getlist('tags'): 19 memo.tags.add(tag) 20 return redirect(reverse('memo:memo_list')) 21 22# 略 23
html
1<!-- memo_create.html --> 2<!DOCTYPE html> 3<html lang="ja"> 4<head> 5 <meta charset="UTF-8"> 6 <title>Memo Create</title> 7</head> 8<body> 9<form method="post" action="{% url 'memo:memo_create' %}"> 10 <table> 11 {% csrf_token %} 12 <input type="hidden" name="csrfmiddlewaretoken" 13 value="U2W58fChfSjAmFz1J55beZXviW7AOi0tyRD52QHxst7MpfCrRfhRoVnss8mWsVZH" kl_vkbd_parsed="true"> 14 <tbody> 15 <tr> 16 <th><label for="title">タイトル:</label></th> 17 <td><input type="text" name="title" maxlength="255" required="" id="title" kl_vkbd_parsed="true"></td> 18 </tr> 19 <tr> 20 <th><label for="content">本文:</label></th> 21 <td><textarea name="content" cols="40" rows="10" id="content"></textarea></td> 22 </tr> 23 <tr> 24 <th><label for="tags">タグ:</label></th> 25 <td><select name="tags" multiple> 26 {% for tag in tag_list %} 27 <option value="{{ tag.pk }}">{{ tag.name }}</option> 28 {% endfor %} 29 </select></td> 30 </tr> 31 </tbody> 32 </table> 33 <button type="submit">作成</button> 34</form> 35</body> 36</html> 37
バージョン
- Python 3.7
- Django 2.2.5
- python-dotenv 0.15.0
回答1件
あなたの回答
tips
プレビュー