Menu
CoddyTech

POST後のリダイレクト

CoddyのDjangoジャーニー「フォーム」セクションの一部。レッスン 3/20。

イベントを追加してから完了ページを再読み込みすると、ブラウザーはフォームをもう一度送信するか確認し、同意するとイベントが二重に追加されます。このページはPOSTへの応答だったため、再読み込みするとPOSTが再送信されます。

この問題を解決するのがPost/Redirect/Getと呼ばれるパターンです。保存後、ビューはリダイレクトを返します。ステータスは302で、新しいアドレスが指定されます。ブラウザーはそのアドレスをGETで開くため、再読み込みしてもGETだけが繰り返されます。

django.shortcutsのredirect()は、{% url %}と同じようにURL名を受け取ります。商品をカートに追加するショップの例です。

from django.shortcuts import redirect


def add_to_cart(request, pk):
    if request.method == "POST":
        CartItem.objects.create(product_id=pk)
        return redirect("shop:cart")
    ...

引数を取るURLには、引数名を指定して渡します。redirect("shop:product", pk=7)。

challenge icon

チャレンジ

簡単

new_eventで、イベントを作成した後、event_added.htmlをレンダリングする代わりに、新しいイベントのページへリダイレクトします。event_added.htmlは削除してもかまいません。もう使われていません。

イベントを追加してからそのページを再読み込みしても、ブラウザーはフォームを再送信するかどうか尋ねません。

自分で試してみよう

from django.shortcuts import get_object_or_404, render

from .models import Event


def event_list(request):
    q = request.GET.get("q", "")
    events = Event.objects.all()
    if q:
        events = events.filter(title__icontains=q)
    return render(request, "events/event_list.html", {"events": events, "q": q})


def event_detail(request, pk):
    event = get_object_or_404(Event, pk=pk)
    return render(request, "events/event_detail.html", {"event": event})


def new_event(request):
    if request.method == "POST":
        Event.objects.create(
            title=request.POST["title"],
            date=request.POST["date"],
            place=request.POST["place"],
        )
        return render(request, "events/event_added.html")
    return render(request, "events/new_event.html")

フォームのすべてのレッスン

自分で練習してみよう: Djangoプレイグラウンド