知識の枝

"All is well"

renderとかredirectとかreverse_lazyとか

約373日前 2021年5月9日16:43
デジタル
Django

改訂履歴


2021/5/9 投稿

1. 背景


Djangoを使った開発中に覚えたことを備忘録として残します。

今回はviews.pyの「テンプレートへのレスポンス」について解説します。


2. 目的


URLを開く処理やhtmlテンプレートを表示する処理について理解を深める。


3. はじめに


Djangoに少しずつ慣れてきてviews.pyのビューを書くようになると、ウェブページを表示させる際の処理で、似たような記述が何種類か出てくることに気が付きます。

それはおそらく「render」「redirect」だと思います。
「reverse_lazy」や「TemplateResponse」も出てきますが、圧倒的に上の2つが多いと思います。

何となく感覚では違いが分かるのですが、再確認の為に調べてみました。


4. renderとredirect


結論を簡単に言うと、

render()は「結果をウェブページに表示」する機能

redirect()は「どのURLを開くか指定」する機能

と表現できると思います。


まずrender()から。
render()のよく見る書き方は下記です。
return render(request, template, context)

第一引数で「requestオブジェクト」を受け取り、
第二引数で「表示するhtmlテンプレート」を指定し、
第三引数で「テンプレートに渡す変数」を指定します。


redirect()のよく見る書き方は下記です。
return redirect('app_name:view_name', id=id)

第一引数で「移動先のURL」を指定し、
第二引数で「urls.pyに渡す変数」を定義します。


どちらも「return re●●」で始まる為、最初はごっちゃになるのだと思います。

簡単に図解するとこんな感じです。



なんとなくでもイメージが伝われば幸いです。


5. TemplateResponseとreverse_lazy


ここはおまけです。
先ほどのrender(), redirect()と同じような場面で使われる2つ。

TemplateResponse と reverse_lazy

これらはクラスベースビュー版のrender()とredirect()と考えて良いと思います。

TemplateResponse ・・・ render()

reverse_lazy ・・・ redirect()



TemplateResponseは自分で書くことが少ないので見覚えがあまり無いかもしれません。

汎用ビューを使ってクラスベースビューを作成する場合、こんな感じで書きますよね。
views.py
class IndexView(generic.TemplateView):
template_name = 'index.html'
model = Model

「template_name」を指定するだけで、内部でrender()と同じことを実行してくれます。

Djangoの汎用ビューの中で「RedirectView」を除く他のビューは全て「TemplateResponseMixin」を継承しています。

まずクラス定義の部分
class TemplateResponseMixin:
template_name = None
template_engine = None
response_class = TemplateResponse
content_type = None


「render_to_response」メソッド
def render_to_response(self, context, **response_kwargs):
response_kwargs.setdefault('content_type', self.content_type)
return self.response_class(
request=self.request,
template=self.get_template_names(),
context=context,
using=self.template_engine,
**response_kwargs
)


「get_template_names」メソッド
def get_template_names(self):
if self.template_name is None:
raise ImproperlyConfigured(
"TemplateResponseMixin requires either a definition of "
"'template_name' or an implementation of 'get_template_names()'")
else:
return [self.template_name]



上記のように「TemplateResponseMixin」には2つのメソッドがあります。
「render_to_response」メソッドと「get_template_names」メソッドです。


「render_to_response」メソッドの中を確認してみましょう。
 return self.response_class(***)
***の部分は省略しています。
このメソッドは自身の「response_class」つまり「TemplateResponse」を返しています。
response_class = TemplateResponse
「TemplateResponse」はrender()と同じような役割と先ほど伝えましたね。

これは公式ドキュメントにも記載されています。こちら

render()¶
render(request, template_name, context=None, content_type=None, status=None, using=None)¶
Combines a given template with a given context dictionary and returns an HttpResponse object with that rendered text.

Django does not provide a shortcut function which returns a TemplateResponse because the constructor of TemplateResponse offers the same level of convenience as render().

Django shortcut functions


TemplateResponse offers the same level of convenience as render(). らしいです。


引数の中で使用するテンプレートを指定しています。
template=self.get_template_names(),
テンプレート名の取得に「get_template_names」メソッドを使用しています。

「get_template_names」メソッドは「template_name」が指定されていないとエラーを吐き、指定されていればその名前を返します。
クラスベースビューの中で「template_name」を指定する必要があるのはこのためです。



続いて「reverse_lazy」についてです。
これは使われ方を見ると一目瞭然なので下記例を見て下さい。
success_url = reverse_lazy(‘app_name:view_name’)
単純にリダイレクト先のURLを指定するのみです。
つまり役割がredirect()と同じだと分かります。


6. さいごに


おまけの部分はさておき、少しでも疑問が解決うできていれば嬉しいです。
お疲れ様でした。