# DjangoのCreateViewに関して
DjangoのCreateViewのまとめ
すぐに忘れてしまうので、CreateViewについて備忘録としてまとめておく
公式サイトのCreateViewの説明
DetailViewのコード
GitHubのCreateViewのコードです。バージョン5.1です
DetialView
オブジェクトの作成、(もしある場合は) バリデーションエラーとフォームの再描画、そしてオブジェクトの保存のフォームを表示するビューです。CreateViewを継承したViewにおいて、1件のオブジェクトを作成するために利用します
簡単に言うと、指定したモデルクラスを1件作成します
簡単なCreateView
基本形です
- 「model」はモデル名として「Monster」を指定します。
- 「fields」で画面に表示するフォームパーツを指定します。
- 「template_name」ではテンプレートファイルを指定します。デフォルトでは、「モデル名_form.html」になります。アプリ名とモデル名でディレクトリ分割したいのでディレクトリで区切ります
- テンプレートで利用するフォームの変数は「form」です
- 「success_url」では、新規登録が正常に完了後にリダイレクトされるURLを指定します。URLを文字列で指定します。DjangoのURL名で指定する場合、「reverse_lazy」で囲みます
from django.views.generic import CreateView
from django.urls import reverse_lazy
from .models import Monster
class MonsterCreateView(CreateView):
model = Monster
fields = ["name", "hp", "mp", "type", "birthday"]
template_name = "study/monster/create.html"
success_url = reverse_lazy("study:monster_list")
テンプレートファイル
対応するテンプレートファイルです。
- base.htmlを作成して、継承します
- django_bootstarap5を利用します
- Bootstrap5でスタイリングします
- フォームの変数名は「object」です
- 一覧のURL:study:monster_list
- 新規作成のURL:study:monster_create
- 更新のURL:study:monster_update
{% extends "base.html" %}
{% load django_bootstrap5 %}
{% block title%}{{ title }}{% endblock %}
{% block content %}
<div class="container mt-4">
<h2 class="mb-4 p-2 bg-primary text-white">Monster Create</h2>
<div class="mb-3">
<a href="{% url 'study:monster_list' %}" class="btn btn-primary">一覧に戻る</a>
</div>
<form action="{% url 'study:monster_create' %}" method="post" novalidate>
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">送信</button>
</form>
</div>
{% endblock %}
ModelFormクラスの作成
Modelクラスと連動したフォームクラスを作成します。ModelFormを継承したMonsterFormクラスを作成します。model, fields, widgetsなどの設定を行います
class MonsterForm( forms.ModelForm):
class Meta:
model = Monster
fields = ['name', 'hp', 'mp', 'type', 'birthday']
widgets = {
'name' : forms.TextInput(attrs={'autofocus' : True}),
'birthday' : forms.TextInput(attrs={'type' : 'date'}),
}
フォームクラスを利用する
model, fieldsの設定を取り除きます。逆に、form_classを指定します。MonsterFormを指定します。これにより、フォームの設定の自由度が増します。各フィールドのwidgetなどを細かく設定可能です。こちらを利用する方が自由度が高い
class MonsterCreateView(CreateView):
form_class = MonsterForm
template_name = "study/monster/create.html"
success_url = reverse_lazy("study:monster_list")
コンテキストにデータを渡す
get_context_dateメソッドをオーバーライドすることで、コンテキストに追加データを渡すことができます。つまり、テンプレートで利用するデータを指定します
class MonsterCreateView(CreateView):
form_class = MonsterForm
template_name = "study/monster/create.html"
success_url = reverse_lazy("study:monster_list")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = self.__class__.__name__
return context
get_form
フォームを取得します。実際の利用としては、フォーム画面を表示する際に、フォームの情報を操作する際に利用します。戻り値はformです
以下の例では、ModelFormの「name」フィールドの初期値として「Slime」を代入します。これにより、テキストボックスに「Slime」が代入されています。
class MonsterCreateView(CreateView):
form_class = MonsterForm
template_name = "study/monster/create.html"
success_url = reverse_lazy("study:monster_list")
def get_form(self):
form = super().get_form()
form.fields["name"].initial = "Slime"
return form
フォームクラスでも初期値の設定は可能ですが、viewで行うことで、動的な値を設定可能になります。例えば、ログインユーザに基づいて、値を設定するなどが可能になります
多対1で結合している場合、多側の新規作成時に1側をセレクトボックスで選択します。セレクトボックスの選択肢として、1側のモデルがすべて選択肢に表示されます。選択肢を絞り込むためにも利用可能です。以下の方法で、1側のモデルの選択肢を変更します
def get_form(self):
form = super().get_form()
form.fields["フィールド名"].queryset = モデル名.objects.filter(xxx=yyy)
return form
form_valid
フォームのサブミット後、バリデーションがエラーが発生しない場合、「form_valid」が呼び出されます。「form_valid」をオーバーライドすることで、バリデーションエラーが未発生後の処理をカスタマイズ可能です。第2引数「form」はユーザが入力した情報を含んだフォームクラスです。戻り値は遷移先のURLを指定します
以下の例では、フォームをそのまま保存しています。単純に新規作成するだけなので、ほぼ意味のない処理です。
from django.shortcuts import redirect
class MonsterCreateView(CreateView):
form_class = MonsterForm
template_name = "study/monster/create.html"
success_url = reverse_lazy("study:monster_list")
def form_valid(self, form):
form.save()
return redirect(self.success_url)
「form_valid」に意味があるのは、以下のようなケースです。フォームクラスのフィールドでモデルに登録するために必要なフィールドをすべて指定していない場合、プログラムで必須フィールドに値を設定する必要があります。その場合、「form_valid」でプログラムで値を代入して、保存します
from datetime import datetime
class MonsterCreateView(CreateView):
form_class = MonsterForm
template_name = "study/monster/create.html"
success_url = reverse_lazy("study:monster_list")
def form_valid(self, form):
# フォームからモデルを取り出します。この時点では保存されない
model = form.save(commit=False)
# モデルの各フィールドに値を代入
model.hp = 100
model.mp = 100
model.type = Monster.TYPE_CHOICES[0][0]
model.birthday = datetime.now()
# モデルを保存。新規作成します
model.save()
# リダイレクトします
return redirect(self.success_url)
form_invalid
フォームのサブミット後、バリデーションエラーが発生した場合、呼び出されるメソッドです
Discussion