Django入門: フォームからPOSTする ~ 簡単な一行掲示板アプリを作る その14【Windows10】
- 作成日: 2020-10-26
- 更新日: 2023-12-26
- カテゴリ: Django
はじめに
この記事は「Djangoで一行掲示板を作ろう」という趣旨のシリーズの記事です。
前回はDjangoのフォームを作って配置しました。
今回はフォームから実際にPOST
リクエストを送信し、そのリクエストを処理したいと思います。
前提として開発環境のOSはWindows10, シェルはコマンドプロンプトです。
仮想環境を使っていますが、仮想環境については第一回の記事をご覧ください。
初期作業フォルダはプロジェクト内のmanage.py
のあるフォルダです。
はじめに
前回までに配置したフォームに投稿内容を入力し、送信ボタンを押すと、フォームから/bbs/
に対してPOST
リクエストを送信できます。
/bbs/
はbbs_home
という名前が付けられ、bbs\views.py
内のhome_view()
に対応付けられています。
ブラウザはPOST
リクエストをWebサーバーに送信するときに一緒にフォームに入力された投稿内容も送信します。
home_view()
でPOST
リクエストを処理し、この投稿内容から新しいPost
モデルのオブジェクトを作成すれば、POST
リクエストに応えてPost
モデルのオブジェクトを作るという処理が書けます。
これらの一連の処理は動的Webサイトの基礎的な処理と言えます。
POST
リクエストをビューで処理するときは、ユーザーからの入力内容が不正かどうか検証(バリデート)し、不正であれば処理を継続せずエラーとしてユーザーに表示するという処理も必要になります。
エラー処理というのは「投稿に失敗しました」とか「入力内容が不正です」とかのメッセージの出力ですね。
このPOST
の処理を書けるようになればDjangoによる動的Webサイトの制作はほぼほぼOKです。
つまり、これを覚えれば色々なアプリを作れるようになるということです。
POSTリクエストをビューで処理する
manage.py
のあるフォルダからエディタでbbs\views.py
を開きhome_view_get()
とhome_view_post()
関数を次のように編集します。
from django.shortcuts import render, redirect # <- redirectを追加
...
def home_view_get(request, form=None):
"""
パス bbs/ の GET
"""
context = {} # コンテキストを作成
context['title'] = '一行掲示板' # ページのタイトル
context['posts'] = Post.objects.all() # Postのリストを取得
if form:
context['form'] = form
else:
context['form'] = PostForm() # フォームを保存
# renderにコンテキストを渡しテンプレートを描画
return render(request, 'bbs/home.html', context)
def home_view_post(request):
"""
パス bbs/ の POST
"""
form = PostForm(request.POST)
if not form.is_valid():
return home_view_get(request, form=form)
form.save()
return redirect('bbs_home')
home_view_get()
はGET
リクエスト、home_view_post()
はPOST
リクエストを処理する関数です。
home_view_get()
も編集してますが、これはhome_view_post()
から再利用するためです。
まず↓の部分ですが、
from django.shortcuts import render, redirect # <- redirectを追加
django.shortcuts
モジュールからredirect
関数を新しくインポートしています。
redirect
関数はページから別のページへリダイレクト(遷移)させる関数です。
次にhome_view_get()
の↓の部分ですが、
def home_view_get(request, form=None):
...
home_view_get()
の引数にform
を加えています。デフォルト値はNone
です。
それから↓の部分ですが、
if form:
context['form'] = form
else:
context['form'] = PostForm() # フォームを保存
home_view_get()
のform
引数がNone
じゃなければその引数をコンテキストに、None
であればPostForm()
で新規作成したオブジェクトを代入しています。
このように処理を書くことで引数form
が指定されている場合に生成するフォームを変更することが可能です。
次にhome_view_post()
です。
def home_view_post(request):
"""
パス bbs/ の POST
"""
form = PostForm(request.POST)
if not form.is_valid():
return home_view_get(request, form=form)
form.save()
return redirect('bbs_home')
まず↓の部分ですが、
form = PostForm(request.POST)
request.POST
はPOST
リクエストのデータが入っているdjango.http.request.QueryDict
です。
これはPythonの辞書(dict
)のようなオブジェクトです。
このQueryDict
をPostForm()
の引数に渡すと、その内容からフォームを構築します。
つまり↑のrequest.POST
にはユーザーの投稿した投稿内容(content
)が入っているわけですが、それをフォームに渡すことでフォームは内部のcontent
にrequest.POST
のcontent
を持つようになります。
言ってしまうとただのデータのコピーです。
次の↓のif
文です。
if not form.is_valid():
return home_view_get(request, form=form)
PostForm
はis_valid()
というメソッドを持っています。
これはフォーム内のデータが不正かどうか判断するメソッドです。
is_valid()
を呼び出すとPostForm
は内部でバリデーション、つまりデータの検証を行います。
バリデーションの結果が不正であればis_valid()
はFalse
を返し、不正でなければTrue
を返します。
つまり↑のif
文は「フォームのデータが不正であれば~」というif
文なわけです。
フォームの内容が不正であれば↑のif
文は検証に使ったフォームをhome_view_get()
に渡して呼び出します。
is_valid()
を呼び出したフォームは内部にエラー情報を持つようになります。
このエラー情報はユーザーに出力することが可能です。
ですのでis_valid()
を呼び出したフォームはコンテキストに保存するようにします。
こうすることでテンプレートからフォームのエラー情報を参照できるようになります。
home_view_post()
からhome_view_get()
を呼び出すのはトンチンカンな気もしますが、こうすることで重複した処理を共通化するようにしています。
今回作っている掲示板は、すべて/bbs/
でGET
とPOST
リクエストを処理していますが、POST
リクエストを/bbs/new/
や/bbs/create/
などのパス(とビュー)に指定することも一般的です。
アプリの規模によってこの辺の設計は考える必要がありますが、今回はごくごく小規模なのでこのような設計にしています。
次に↓の部分です。
form.save()
return redirect('bbs_home')
PostForm
はforms.ModelForm
を継承したクラスですが、ModelForm
を継承したフォームはsave()
メソッドを呼び出すことで内部データを利用してモデルのオブジェクトを作成することが出来ます。
↑のform.save()
の返り値はbbs.models.Post
, つまり今回作成した掲示板の投稿用モデルです。
しかしこの処理では返り値は使わないので保存していません。
最後にredirect('bbs_home')
を呼び出してbbs_home
にページをリダイレクトしています。
redirect()
関数の第1引数にはパスかルート名を渡します。
is_valid()
を使ったif
文ではhome_view_get()
に処理を委譲していましたが、ここではリダイレクトです。
これはブラウザのリロードによるフォームからの2重送信を防ぐための処置です。
ためしにredirect()
をhome_view_get()
に書き換えて、フォームから投稿した後にページをリロードしてみてください。どういうことかわかると思います。
動作確認
これでPOST
リクエストの処理は完了です。
開発用サーバーを起動します。
> python manage.py runserver 0.0.0.0:8123
エラーがなければ↓のように掲示板へ投稿できるようになっているはずです。
おわりに
今回までで掲示板としての形は一応整いました。
不格好ですがちゃんとした動的Webサイトです。
🦝 < おめでとうございます
次回から掲示板に微修正を加えていきます。
🐭 < おたのしみに