Djangoの華麗なるCreateViewの使い方
目次
- Djangoの華麗なるCreateViewの使い方
- 前提とするモデルの定義
- CreateViewを使ったビューの定義
- テンプレートファイルの作成
- ルート情報(urls.py)の編集
- ビューの改造
- おわりに
Djangoの華麗なるCreateViewの使い方
Djangoではビューを作成する場合、あらかじめDjango側が用意している汎用ビューを使うことが出来ます。
汎用ビューを使うとコードの量を減らすことが可能です。
この記事ではモデルの作成に使われる汎用ビュー、CreateViewの使い方を解説します。
このCreateView
を使うとモデルの投稿ロジックを簡単に書くことが出来ます。
具体的にCreateView
について↓を見ていきます。
前提とするモデルの定義
CreateViewを使ったビューの定義
テンプレートファイルの作成
ルート情報(urls.py)の編集
ビューの改造
関連記事
DjangoのDetailViewのかしこい使い方【Python】
DjangoのListViewのうまい使い方【Python】
参考
CreateView | Generic editing ビュー | Django ドキュメント | Django
django/edit.py at main · django/django
前提とするモデルの定義
今回の解説で使うモデルは、Post
というモデルです。
掲示板アプリを作成するという前提で、このような「投稿」を表現するモデルを定義します。
from django.db import models from django.core.validators import MinLengthValidator class Post(models.Model): name = models.CharField(max_length=32, help_text='投稿者名', validators=[MinLengthValidator(3, '3文字以上です')]) content = models.TextField(max_length=1024, help_text='投稿内容')
Post
のフィールドはname
とcontent
です。
name
は投稿者名で、content
は投稿内容を表します。
name
にはバリデーターMinLengthValidator
を設定しています。name
の長さが3文字より下だとエラーになります。
CreateViewを使ったビューの定義
Djangoの汎用ビューであるCreateView
を使ってビューを定義します。
from django.shortcuts import render from django.views.generic import DetailView, CreateView from core.models import Post from django.urls import reverse ... class PostDetail(DetailView): model = Post class PostCreate(CreateView): model = Post fields = ['name', 'content'] def get_success_url(self): return reverse('posts-detail', kwargs={'pk': self.object.pk}) ...
PostDetail
というのはPost
のディティール(詳細)を表示するビューです。
これの詳細については↓をご覧ください。
DjangoのDetailViewのかしこい使い方【Python】
PostCreate
が本題のビューで、こちらはCreateView
を継承しています。
PostCreate
の属性のmodel
にはモデルを代入します。
今回はPost
モデルの作成を行うのでPost
モデルを入れています。
fields
にはフォームに表示させるフィールド名を指定します。
今回はユーザーに、Post
モデルのname
とcontent
をフォームに入力してもらうので、これらを指定します。
get_success_url()
メソッドを上書きしていますが、これは投稿が成功したときに遷移するページのURLを返すメソッドです。
今回はreverse()
を使ってposts-detail
のURLへ遷移するようにしています。
posts-detail
は後述するurls.py
で定義が見れますが、PostDetail
ビューのページです。
つまりPostCreate
でユーザーにフォームを表示し、そのフォームに入力してもらって投稿を行ってもらい、投稿に成功したらPostDetail
ビューのページを表示するという感じの設計になります。
テンプレートファイルの作成
PostCreate
ビューで表示するテンプレートファイルを作成します。
↓のコードをアプリ名/templates/アプリ名/post_form.html
に保存します。
<form action="{% url 'posts-create' %}" method="POST"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="投稿" /> </form>
PostCreate
ビューは内部でフォームを作成します。
このフォームはコンテキストにform
という名前で保存されます。
そのため↑のようにforms.as_p
とやるとform
の内容が表示されます。
フォームのaction
にはposts-create
のURLを指定します。
これは後述のurls.py
で定義が見れますが、PostCreate
ビューを指しています。
method
はPOST
です。
csrf_token
も忘れずに描画しておくようにします。
post_form.html
というファイル名は今までに指定してませんが、これは暗黙的に決定されます。
PostCreate
ビューはtemplate_name_suffix
という属性を持っています。
これの値はデフォルトでは_form
になっています。
PostCreate
ビューは内部でテンプレートファイル名を合成しますが、このtemplate_name_suffix
とモデル名を合体させて合成します。
その結果がpost_form
になるわけです。
template_name_suffix
の値を変更すればたとえばpost_create_form.html
というようなファイル名にすることも可能です。
ちなみにPostDetail
のテンプレートファイルは↓のようになります。
名前はpost_detail.html
で保存します。
<p>name: {{ post.name }}</p> <p>content: {{ post.content }}</p>
(^ _ ^) | 手抜きやね |
(・ v ・) | そうだね |
ルート情報(urls.py)の編集
最後にルート情報を定義します。
name=posts-detail
がPostDetail
ビューで、name=posts-create
がPostCreate
ビューになります。
from django.contrib import admin from django.urls import path from core import views urlpatterns = [ path('admin/', admin.site.urls), path('posts/detail/<int:pk>/', views.PostDetail.as_view(), name='posts-detail'), path('posts/create/', views.PostCreate.as_view(), name='posts-create'), ]
以上を定義すると、ブラウザで/posts/create/
にアクセスするとフォームが表示されます。
そしてフォームにデータを入力し、投稿ボタンを押すと/posts/detail/<int:pk>/
に遷移します。
ビューの改造
CreateView
のメソッドを上書きすることでその振る舞いを上書きすることが出来ます。
post()の上書き
post()
メソッドを上書きすると、POST
時のビューの振る舞いをハンドリングすることが可能です。
class PostCreate(CreateView): ... def post(self, request, *args, **kwargs): self.object = None return super().post(request, *args, **kwargs)
super().post()
を呼び出すのを忘れないようにします(return
も忘れずに)。
これが無いとPOST
が処理されません。
get_form()でフォーム詳細を設定
get_form()
メソッドを上書きすると、フォームの詳細な設定を行うことが可能です。
class PostCreate(CreateView): ... def get_form(self, form_class=None): form = super().get_form(form_class) form.fields['name'].label = 'お名前' form.fields['content'].required = False return form
form_invalid()でエラー時のレスポンスを変更
form_invalid()
はform.is_valid()
がFalse
の時に呼ばれます。
True
の時に呼ばれるのはform_valid()
です。
form_invalid()
は返り値でレスポンスを返し、これが描画されます。
form_invalid()
を上書きすれば、エラー時のレスポンスを変更することが可能です。
class PostCreate(CreateView): ... def form_invalid(self, form): response = super().form_invalid(form) return response
↑は普通に機能します。↓のようにすると動作を上書きできます。
from django.http import HttpResponse class PostCreate(CreateView): ... def form_invalid(self, form): return HttpResponse('失敗しました', status=500)
get_context_data()でコンテキストを弄る
get_context_data()
を上書きするとコンテキストを弄れます。
コンテキストとは、テンプレートファイルで参照される辞書のことです。
form
などの変数もこのコンテキストに保存されています。
class PostCreate(CreateView): ... def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['message'] = 'ご自由に投稿してください。' return context
↑の場合はコンテキストにmessage
という変数を追加しています。
こうすることでpost_form.html
でmessage
変数を参照できます。
<p>{{ message }}</p> <form action="{% url 'posts-create' %}" method="POST"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="投稿" /> </form>
おわりに
今回はDjangoの汎用ビュー、CreateView
について見てみました。
汎用ビューを使えば楽にアプリを作ることが出来ます。
(^ _ ^) | 汎用ビューは正義 |
(・ v ・) | すんばらし |