January 20, 2021
←前回:Day 14 DetailViewを使った詳細表示画面の作成
「Djangoを学びたい!」とのことでありましたら[Day 1]Djangoの開発環境から読むことをおすすめします。
#はじめに
今回は簡単なトピック投稿画面の作成をします。
では掲示板の新規トピックを登録する画面を作っていきましょう。
まずはフォームがあるだけのシンプルな登録画面を作ります。
登録が完了するとTOP画面に作成したトピックが表示されるようにしましょう。
#トピック登録画面のテンプレート作成
新しい画面を作成するのでまずはテンプレートを作りましょう。
作成ファイルの場所は、templates/thread/create_topic.htmlです。
{% extends 'base/base.html' %}
{% block title %}トピック作成 - {{ block.super }}{% endblock %}
{% block content %}
<div class="ui grid stackable">
<div class="eleven wide column">
<div class="ui breadcrumb">
<a href="{% url 'base:top' %}" class="section">TOP</a>
<i class="right angle icon divider"></i>
<a class="active section">トピック作成</a>
</div>
<div class="ui segment">
<div class="content">
<div class="header"><h3>トピック作成</h3></div>
<form class="" action="{% url 'thread:create_topic' %}" method="POST">
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="ui button">作成</button>
</form>
</div>
</div>
</div>
{% include 'base/sidebar.html' %}
</div>
{% endblock %}
キーポイントが二つあります。1つは{% csrf_token %}ですね。
これはクロスサイトリクエストフォージェリという脆弱性に対するセキュリティ対策でトークンによって認証されないリクエストは受け付けない仕組みです。POSTメソッドでは必須です。(意図的csrf_tokenなしでアクセスすることもできますが、セキュリティ上の脆弱性を熟考の上判断して下さい。)
もう一つは{{form.as_p}}ですね。
これはビュー側から’form’というコンテキストを受け取るために記述しているのですが、もう少し先で解説します。
ここで私は{% csrf_token %}に関しては理解できたのですが、{{form.as_p}}に関しては「???」になってしまいました。
#フォームを使う
さて、ここでフォームというものが登場します。
フォームというとHTMLの入力フォームを思い浮かべると思いますが、Djangoにおけるフォーム機能はもう少し幅の広い機能を提供します。
ウェブアプリがフォームを持つ場合、以下のような処理が必要にあります。
・データをレンダリングするための準備
・HTMLとしてフォームをレンダリングすること
・フォームから送信されたデータを処理すること
Djangoではフォームというパーツがこれらの処理を守備範囲として受け持ちます。詳細は公式ドキュメントも参照下さい。
フォームにはついては別の機会にもう少し詳しく扱う予定ですが、ここではとにかく使ってみましょう。
今回はModelFormというフォームを使います。まず、thread/forms.pyを作成します。
from django.forms import ModelForm
from . models import Topic
class TopicCreateForm(ModelForm):
class Meta:
model=Topic
fields=[
'title',
'user_name',
'category',
'message',
]
ModelFormを継承したTopicCreateFormを用意します。
ModelFormを継承したクラスはMetaクラスにmodelとfieldsを指定することでフォームを作成出来ます。
今回のようにモデルに対応するフォームを作成する場合は便利な方法です。(今回は扱いませんが、ModelFormを使わずフォームを生成する方法も当然あります。)
#ビューを作成する
次にthread/views.pyに関数ベースのビューを追加していきます。
from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from . forms import TopicCreateForm
from . models import Topic
def topic_create(request):
template_name = 'thread/create_topic.html'
ctx = {}
if request.method == 'GET':
ctx['form'] = TopicCreateForm()
return render(request, template_name, ctx)
if request.method == 'POST':
topic_form = TopicCreateForm(request.POST)
if topic_form.is_valid():
topic_form.save()
return redirect(reverse_lazy('base:top'))
else:
ctx['form'] = topic_form
return render(request, template_name, ctx)
GETメソッドでアクセスされた場合とPOSTメソッドでアクセスされた場合に処理を分けています。
とくに明示しない場合はGETでのアクセスとして扱われます。
TopicCreateFormのインスタンスをコンテキストで渡しています。
これがthread/create_topic.htmlで描写されるというわけです。
テンプレートの部分で説明を保留していましたが、先程フォームにはHTMLフォームとしてレンダリングする機能もあると説明しました。
一番簡単なレンダリングは{{form}}とすることです。
これは単順にHTMLのinputタグとlabelタグを並べるだけです。
これをもう少し整形するための手法が以下の方法です。
{{form.as_p}} : Pタグで囲んで段落毎に整形する。
{{form.as_ul}} : LIタグで囲んでリスト整形表示する。ただしULタグは別途記載する必要あり
{{form.as_table}}:テーブル表示するための整形。ただしTABLEタグは別途記載する必要あり
今回はform.as_pを使って整形したということです。
もうお気づきかも知れませんが、as_p, as_ul, as_tableはそれぞれ整形されたHTMLタグを返す関数です。
POSTメソッドで受けた場合にはis_valid()関数を呼んでデータの精査を行います。
今回はModelFormを使用しているためTopicモデルが有している情報に適しているか精査されます。
文字の長さやNullの許容等が正しくない場合は精査に失敗します。
正しいデータが来た場合はフォームのsave()関数を呼んで保存しています。
この方法はModelFormの場合のみ使える方法です。
ややこしいので別の機会に触れます。データの精査に失敗した場合はtopic_formにエラーメッセージが入っていますので、これをコンテキストとして渡して再度create_topic.htmlを表示します。
(私は何が何のことだかさっぱりわかりませんでした。)
では、追加した関数とURLを結びつけるためにthread/urls.pyに追加していきます。
from django.urls import path
from . import views
app_name = 'thread'
urlpatterns = [
path('create_topic/', views.topic_create, name='create_topic'),
]
これで準備は整いました。localhost:8080/thread/create_topic/にアクセスしてみましょう。
#おわりに
だんだんとQiitaに投稿することが慣れてきました。
初期は「どうやって投稿するんだろう?」「こんな記事を投稿しいていいのか?」などの不安がありましたが、慣れてきました。
とか言って、急にやめてしまうパターンもなくはないので今後どうなるかは、「神のみぞ知る」って感じですね。(何言ってんだよ)
それではまたまた