Django入門: フォームを配置する ~ 簡単な一行掲示板アプリを作る その13【Windows10】
- 作成日: 2020-10-24
- 更新日: 2023-12-26
- カテゴリ: Django
はじめに
この記事は「Djangoで一行掲示板を作ろう」という趣旨のシリーズの記事です。
前回までにDjangoのプロジェクトとアプリを作成し、ルート情報とビューを接続し、テンプレートを描画して、モデルを作りマイグレーションを行い、ビューでオブジェクトを取得し、管理サイトでオブジェクトを追加してテンプレートで表示して、フォームを作るというところまでやりました。
今回からDjangoのフォームを実際に配置していきたいと思います。
前提として開発環境のOSはWindows10, シェルはコマンドプロンプトです。
仮想環境を使っていますが、仮想環境については第一回の記事をご覧ください。
初期作業フォルダはプロジェクト内のmanage.py
のあるフォルダです。
ビューからコンテキストにフォームを保存
manage.py
のあるフォルダからbbs\views.py
を開きます。
これを次のように編集します。
from bbs.forms import PostForm # <- これを追加
まず、↑のように前回作成したPostForm
をインポートします。
def home_view_get(request):
context = {}
context['title'] = '一行掲示板'
context['posts'] = Post.objects.all()
context['form'] = PostForm() # <- これを追加
return render(request, 'bbs/home.html', context)
それから↑のようにhome_view_get()
を編集します。
追加したのは↓の行です。
context['form'] = PostForm() # <- これを追加
コンテキストにform
という変数を作り、そこにPostForm
のオブジェクトを保存しています。
このform
はテンプレートで利用することになります。
ここまでのコードの全文は↓のようになります。
from django.shortcuts import render
from django.http import HttpResponse
from bbs.models import Post
from bbs.forms import PostForm # <- これを追加
def home_view(request):
# request.methodによって処理を分岐
if request.method == 'GET':
return home_view_get(request)
elif request.method == 'POST':
return home_view_post(request)
else:
return HttpResponse('invalid method', status=400)
def home_view_get(request):
"""
パス bbs/ の GET
"""
context = {} # コンテキストを作成
context['title'] = '一行掲示板' # ページのタイトル
context['posts'] = Post.objects.all() # Postのリストを取得
context['form'] = PostForm() # <- これを追加
# renderにコンテキストを渡しテンプレートを描画
return render(request, 'bbs/home.html', context)
def home_view_post(request):
"""
パス bbs/ の POST
"""
return HttpResponse('TODO') # 後で実装
編集した行は2行だけですが、これでビューの編集は終わりです。
テンプレートにフォームを配置
次にmanage.py
のあるフォルダからbbs\templates\bbs\home.html
を開きます。
これを次のように編集します。
{% extends 'bbs/base.html' %}
{% block content %}
<h1>{{ title }}</h1>
<form method="POST" action="{% url 'bbs_home' %}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">投稿する</button>
</form>
<ul>
{% for post in posts %}
<li>{{ post.id }}: {{ post.content }}</li>
{% endfor %}
</ul>
{% endblock %}
追加したのは↓の部分です。
<form method="POST" action="{% url 'bbs_home' %}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">投稿する</button>
</form>
form
タグのmethod
属性にはフォームで使用するメソッドを指定します。
今回の場合は掲示板への投稿になるのでメソッドはPOST
です。
それからaction
属性にはリクエスト先のパスを指定します。
action="{% url 'bbs_home' %}
{% url %}
にパスの名前を指定するとその名前が参照され、パスが出力されます。
↑ではbbs_home
を指定していますが、これはbbs\urls.py
内で指定している名前です。
↓の部分のname='bbs_home'
がそうです。
path('', home_view, name='bbs_home'), # ルートにhome_viewを指定
bbs_home
を解決すると/bbs/
というパスになります。
次に↓の部分ですが、
{% csrf_token %}
↑はフォーム内にCSRF
トークンを配置しています。
CSRF
トークンとは悪意のあるアタッカーによるCSRF
攻撃を防ぐための仕組みです。
CSRF
とCSRF
トークンの仕組みについては↓の記事をご覧ください。
Djangoではフォームからの送信についてはこのCSRF
トークンを配置するのが普通になっています。
これはWebアプリのセキュリティを守るためです。
このCSRF
トークンの仕組みがないと、Webアプリに脆弱性が生まれ、悪意のあるアタッカーにWebアプリを悪用される可能性が高くなってしまいます。
また、ビューでこのCSRF
トークンの仕組みを無効化することは可能です。
次に↓の部分ですが、
{{ form.as_p }}
↑はフォームの部品(input
タグ)を出力しています。
as_p
というのはform
のメソッドまたは属性です。
テンプレートではメソッドの呼び出しにカッコをつけません。
このas_p
というのはフォームの部品をp
タグで囲って出力するというメソッドです。
次に↓の部分です。
<button type="submit">投稿する</button>
これは送信ボタンです。
フォームを表示
では開発用サーバーを起動して動作確認してみます。
> python manage.py runserver 0.0.0.0:8123
特に問題が無ければ↓のように表示されると思います。
HTMLソースを見てみると↓のようなHTMLが出力されています。
<h1>一行掲示板</h1>
<form method="POST" action="/bbs/">
<input type="hidden" name="csrfmiddlewaretoken" value="xxxx">
<p><label for="id_content">Content:</label> <input type="text" name="content" maxlength="140" required="" id="id_content"> <span class="helptext">掲示板のポスト内容</span></p>
<button type="submit">投稿する</button>
</form>
<ul>
<li>1: てすと1</li>
<li>2: てすと2</li>
<li>3: てすと3</li>
</ul>
CSRF
トークンは↓のようにhidden
なinput
タグとして出力されています。
この値は環境によって変わります。
<input type="hidden" name="csrfmiddlewaretoken" value="xxxx">
form.as_p
で出力されたタグは↓のように出力されています。
<p><label for="id_content">Content:</label> <input type="text" name="content" maxlength="140" required="" id="id_content"> <span class="helptext">掲示板のポスト内容</span></p>
↑を見るとPost
モデルのcontent
フィールドのmax_length
がそのままinput
タグのmaxlength
に流用されていることがわかります。
おわりに
今回はフォームを配置して出力する所までやってみました。
次回からビューのPOST
メソッドを実装して、実際に投稿できるようにしていきたいと思います。
🦝 < フォームを信じよ