超初心者用: Djangoでウェブアプリを作る ⑤ユーザーによるentryの追加
前回までにユーザーが新しいトピックを追加することができるようになりました。今回は Entry を入力できるようにします。手順はおなじみの、URL の決定、view function と template の記入、ページへのリンクです。しかし、まずは form.py にクラスを追加します。
Entry ModelForm
Entry モデルのためのフォームを作らなければなりません。今回は少し異なります。
# form.py from django import forms from .models import Topic, Entry class TopicForm(forms.ModelForm): # --省略-- class EntryForm(forms.ModelForm): class Meta: model = Entry fields = ['text'] labels = {'text': ''} widgets = {'text': forms.Textarea(attrs={'cols': 80})}
まずは、Topic と同様に Entry クラスをインポートします。Metaクラスをネストしてある forms.ModelForm からの EntryForm クラスを作ります。ここでも text フィールドを与えます。
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
widgets attribute を使って、text box の横幅の大きさを設定します。今回は横に80 columns に設定しています。ちなみにデフォルトでは40となっています。
new_entry URL
新しい entry を追加するときには、特定のトピックに結び付けるのでURL に topic_id を含めなければなりません。
# practicing_logs/urls.py #--省略-- urlpatterns = [ #--省略-- # 新しい entry の追加ページ url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'), ]
new_entry() view function
この view function は new_topic とほとんど一緒です。
# views.py from django.shortcuts import render #--省略-- from .models import Topic from .forms import TopicForm, EntryForm #--省略-- def new_entry(request, topic_id): """特定のトピックに entry を追加""" topic = Topic.objects.get(id=topic_id) if request.method != 'POST': # 空欄 form = EntryForm() else: # POST data が送られた form = EntryForm(data=request.POST) if form.is_valid(): new_entry = form.save(commit=False) new_entry.topic = topic new_entry.save() return HttpResponseRedirect(reverse('practicing_logs:topic', args=[topic_id])) context = {'topic': topic, 'form': form} return render(request, 'practicing_logs/new_entry.html', context)
先ほど作成した EntryForm をインポートします。new_entry() はURL から受け取る topic_id parameter を持っています。
topic = Topic.objects.get(id=topic_id)
受け取った id に呼応するトピックを取得します。
if request.method != 'POST':
リクエストが POST か GET なのかを確認します。GET であれば空欄の EntryForm を作成します。POST であれば、入力されたデータで処理します。
if form.is_valid():
入力されたデータが適切なフォーマットであるかを確認し、適切であれば save() を実行します。commit==False はデータベースに保存することなく、entry を作成し、new_entry に保存します。new_entry のトピックを決定したら save() を実行します。これはデータベースに保存されます。
return HttpResponseRedirect(reverse('practicing_logs:topic', args=[topic_id]))
無事に追加できたら、topic ページにリダイレクトします。
new_entry template
このテンプレートも new_topic の時のものと似ています。
# new_entry.html {% extends "practicing_logs/base.html" %} {% block content %} <p><a href="{% url 'practicing_logs:topic' topic.id %}">{{ topic }}</a></p> <p>Add a new entry:</p> <form action="{% url 'practicing_logs:new_entry' topic.id %}" method='post'> {% csrf_token %} {{ form.as_p }} <button name='submit'>add entry</button> </form> {% endblock content %}
<p><a href="{% url 'practicing_logs:topic' topic.id %}">{{ topic }}</a></p>
一番上にはどのトピックに入力しようとしているのかを分かりやすくするために、トピック名を表示させます。
<form action="{% url 'practicing_logs:new_entry' topic.id %}" method='post'>
action argument は URL の topic_id を含んでいます。
new_entry ページにリンクする
それぞれのトピックページから entry を追加するページに飛べるようにします。
# topic.html {% extends "practicing_logs/base.html" %} {% block content %} <p>Topic: {{ topic }}</p> <p>Entries:</p> <p> <a href="{% url 'practicing_logs:new_entry' topic.id %}">add new entry</a> </p> <ul> #--省略-- </ul> {% endblock content %}
既存の entry を見せる前に 新しい entry を追加するためのリンクを継和得ます。下の画像のような感じになります。