導入
投稿や登録は POST で送ります。ただし POST には「なりすまし送信(CSRF)」という攻撃があり、Django は既定でそれを防いでいます。仕組みを理解しておきましょう。
説明
CSRF(クロスサイト・リクエスト・フォージェリ) は、悪意あるサイトがユーザーになりすまして、あなたのサイトへ勝手に POST を送る攻撃です。Django はこれを防ぐため、POST フォームに秘密のトークンを埋め込み、送信時に照合します。テンプレートでは {% csrf_token %} を書くだけです。
<form method="post">
{% csrf_token %} <!-- これが無いと本番では 403 で拒否される -->
<input name="title">
<button>投稿</button>
</form>
ビュー側は、GET(フォーム表示)と POST(受け取り)を分けて書きます。
import django
from django.conf import settings
if not settings.configured:
settings.configure(DEBUG=True, SECRET_KEY="dev",
ROOT_URLCONF=__name__, ALLOWED_HOSTS=["testserver"])
django.setup()
from django.http import HttpResponse
from django.shortcuts import redirect
from django.urls import path
posts = []
def create(request):
if request.method == "POST":
title = request.POST.get("title", "").strip()
if title:
posts.append(title)
return redirect("/") # 保存後は一覧へリダイレクト(PRGパターン)
return HttpResponse("投稿一覧: " + " / ".join(posts))
urlpatterns = [path("", create)]
from django.test import Client
client = Client()
client.post("/", {"title": "はじめての投稿"})
client.post("/", {"title": "2件目"})
print(client.get("/").content.decode()) # 投稿一覧: はじめての投稿 / 2件目
request.POST.get("title")… 送信されたフォームの値を読む。- 保存後に
redirect("/")するのは PRG(Post/Redirect/Get) という定番。これでブラウザの「更新」による二重投稿を防げます。 - このコースのテストクライアントは学習のため CSRF チェックを省いています。本物のフォームでは、上記の
{% csrf_token %}を必ず入れてください。入れないと Django は 403(拒否)を返します。
やってみよう
client.post("/", {"title": "..."}) を何度か呼んでから client.get("/") を見て、投稿が貯まることを確かめましょう。title を空文字にすると if title: により保存されないことも確認できます。
演習
空白だけの投稿(例 " ")が保存されないことを利用しています。create を改造して、保存に成功したときだけ末尾に何件貯まったかを含めた文字列を返す代わりに、/ の一覧表示を 件数: N 件(内容: ...) の形式に変えてください。print(client.get("/").content.decode()) に 件数: が含まれれば成功です。
ヒント1を見る
GET 側の return HttpResponse(...) を f"件数: {len(posts)} 件(内容: {' / '.join(posts)})" にします。