◀ 5.

【django】viewからtemplateへの遷移方法(パラメータありなし)

この記事の要点
  • View からテンプレートを表示するには render(request, 'テンプレート名', context) を return する
  • テンプレートに値を渡すときは第 3 引数の辞書(context)に入れ、テンプレートでは {{ キー名 }} で参照する
  • 別の URL に移動させたいときは redirect()。渡すのはテンプレート名ではなく URL 名や URL
  • フォームの POST 処理の後は render ではなく redirect する(二重送信防止)
  • テンプレートが見つからないときは、置き場所と TEMPLATES 設定を確認する

render と redirect の違い

Django の View から画面を表示する方法は、大きく分けて 2 つあります。名前が似ていますが役割はまったく違うので、最初に整理しておきます。

関数何をするかブラウザの URL主な用途
render()テンプレートに値を埋め込んだ HTML をその場で返す変わらない一覧・詳細・フォームの表示
redirect()「この URL に移動して」という 302 応答を返す移動先に変わる登録・更新・ログイン後の画面移動
HttpResponse()文字列をそのまま返す変わらない動作確認、簡単なテキスト応答

パラメータなしでテンプレートを表示する

最もシンプルな形です。render は django.shortcuts からインポートします。

from django.shortcuts import render

def index(request):
    return render(request, 'index.html')

第 2 引数のテンプレート名は、設定されたテンプレートディレクトリからの相対パスです。アプリ内の templates フォルダに置く場合は、myapp/templates/myapp/index.html のようにアプリ名のフォルダを 1 段挟み、render(request, 'myapp/index.html') と書くのが定石です。別のアプリに同名の index.html があっても取り違えずに済みます。

パラメータありでテンプレートを表示する

テンプレートに値を渡すには、第 3 引数に辞書(context)を渡します。

from django.shortcuts import render

def index(request):
    item_list = ['a', 'b', 'c']
    context = {
        'item_list': item_list,
    }
    return render(request, 'index.html', context)

テンプレート側では、辞書のキー名で値を参照します。リストは {% for %} で繰り返し表示できます。

<ul>
{% for item in item_list %}
    <li>{{ item }}</li>
{% empty %}
    <li>データがありません</li>
{% endfor %}
</ul>

モデルから取得したデータも同じように渡せます。context = {'users': User.objects.all()} としておけば、テンプレートで {{ user.name }} のように属性を参照できます。なお、テンプレートに出力した値は自動で HTML エスケープされます。

リダイレクトする

redirect() はテンプレートを表示するのではなく、別の URL へ移動させる関数です。引数には、urls.py で付けた URL 名、URL のパス、またはモデルのインスタンスを渡せます。

from django.shortcuts import redirect

def index(request):
    # urls.py で name='top' を付けたパスへ移動
    return redirect('top')

def go_home(request):
    # パスを直接書くこともできる
    return redirect('/')

def after_save(request, pk):
    # URL にパラメータが必要な場合はキーワード引数で渡す
    return redirect('item_detail', pk=pk)

redirect('index.html') のようにテンプレート名を渡すのはよくある間違いです。この場合 Django は index.html という URL 名を探し、見つからなければ相対 URL として扱うため、意図しないパスに移動して 404 になります。テンプレートを表示したいなら render を使い、移動したいなら URL 名を渡します。

リダイレクト先に値を渡したい場合は、URL のパラメータに含めるか、クエリ文字列を付けるか、一時的な通知ならメッセージフレームワーク(django.contrib.messages)を使います。render のように辞書を直接渡すことはできません。

フォーム送信後は redirect する(PRG パターン)

POST でデータを登録した後に render で完了画面を返すと、ユーザーがブラウザを再読み込みしたときに同じ POST が再送され、二重登録になります。登録処理の後は redirect で別の URL に移動させ、移動先を GET で表示するのが定石です(Post/Redirect/Get パターン)。

from django.shortcuts import render, redirect

def item_create(request):
    if request.method == 'POST':
        name = request.POST.get('name', '')
        # ...保存処理...
        return redirect('item_list')
    return render(request, 'myapp/item_form.html')

うまく表示されないときの確認ポイント

  • TemplateDoesNotExist: テンプレートの置き場所と名前を確認します。アプリ内の templates を使うなら settings.py の TEMPLATES で 'APP_DIRS': True、プロジェクト直下の templates を使うなら 'DIRS' にパスを登録し、アプリが INSTALLED_APPS に入っているかも確認します。エラー画面の「Template-loader postmortem」に、探したパスが一覧表示されます
  • NoReverseMatch: redirect に渡した URL 名が urls.py の name と一致していない、または必要なパラメータが足りません。アプリに app_name を付けている場合は 'myapp:item_list' のように名前空間付きで指定します
  • 値が表示されない: context のキー名とテンプレートの変数名が一致しているか確認します。存在しない変数はエラーにならず空文字として表示されるため、気づきにくい点に注意します

関連

Post Share
子ページ

子ページはありません

同階層のページ
  1. ビュー(View)
  2. テンプレート(Template)
  3. モデル(Model)
  4. ルーティングの作成
  5. viewからtemplateへの遷移方法