Django Modelformで保存するモデルのフィールドを設定する方法

ModelFormを使うとモデルのフォームを簡単に作成し保存する事ができますが、手動でモデルのフィールドを設定したいケースもあります。

今回はModelFormを使う時に、手動でモデルのフィールドを設定する方法を2つ紹介します。関数ベースビューとクラスベースビューのどちらの書き方も紹介します。

おすすめは「方法2 save(commit=False)を使う」の”クラスベースビュー”の実装方法です。

モデルとフォームの作成

以下の様なタグ名と更新者のデータを持つTagモデルを作成します。

from django.db import models
from django.contrib.auth.models import User

class Tag(models.Model):
    name = models.CharField('タグ名', max_length=100)
    updated_by = models.ForeignKey(User, on_delete=models.CASCADE)

このTagモデル用のフォームは次の様になります。(Tagモデルのインポート分は省略しています)

from django.forms import ModelForm

class TagForm(ModelForm):
    class Meta:
        model = Tag
        fields = ['name']

タグ名はユーザーに入力してもらうため fields = [‘name’] としています。updated_byは手動で設定するためfieldsには含めません。

次から本題です。updated_byを手動で設定する方法を4つ紹介します。

方法1 最初にインスタンスを作成する

1つ目の方法は最初にインスタンスを作成する方法です。Tagモデルのインスタンス作成時に更新者を設定し、TagFormの引数に作成したインスタンスを渡します。

関数ベースビュー

関数ベースのビューに書く場合のコードは以下の様になります。このコードは公式サイトで紹介されている方法です。

tag = Tag(updated_by=request.user)
form = TagForm(request.POST, instance=tag)
form.save()

クラスベースビュー CreateViewを使う場合

django.views.generic.editのCreateViewクラスを継承している場合は、以下の様にpostメソッドをオーバーライドすれば設定できます。

def post(self, request, *args, **kwargs):
    self.object = Tag(updated_by=self.request.user)
    return super(BaseCreateView, self).post(request, *args, **kwargs)

方法2 save(commit=False)を使う

2つ目の方法はsave(commit=False)を使う方法です。commit=Falseを設定するとデータベースにまだ保存されていないオブジェクトを返します。

関数ベースビュー その1

関数ベースのビューに書く場合のコードは以下の様になります。このコードは公式サイトで紹介されている方法です。

form = TagForm(request.POST)
tag = form.save(commit=False)
tag.updated_by = request.user
tag.save()

関数ベースビュー その2 saveメソッドをオーバーライド

saveメソッドをオーバーライドしても実現できます。

状況にもよりますが、「関数ベースビュー その1」の様に関数ベースビュー内にフィールドを編集するより、saveメソッドをオーバーライドした方が保守しやすいと思います。この場合のコードは以下の様になります。

class TagForm(ModelForm):
    class Meta:
        model = Tag
        fields = ['name']

    def save(self, user):
        obj = super.save(commit=False)
        obj.updated_by = user
        obj.save()
	return obj

関数ベースのビューでTagForm使うコードは以下の様になります。「関数ベースビュー その1」よりシンプルになりました。

form = TagForm(request.POST)
tag = form.save(request.user)

クラスベースビュー

「関数ベースビュー その2 saveメソッドをオーバーライド」で紹介したTagFormをクラスベースビューで使う方法です。私はこの方法が一番気に入っています。

CreateViewやUpdateView継承しているクラスベースビューの場合はform_validメソッドをオーバーライドすれば良いです。

def form_valid(self, form):
    self.object = form.save(self.request.user)
    return HttpResponseRedirect(self.get_success_url())

まとめ

ModelFormを使う時に手動でモデルのフィールドを設定する方法を複数紹介しました。どの方法を取るかは人それぞれですが、自分にとって一番開発・保守しやすい方法は何かを考えて適切な方法を選びましょう。

スポンサーリンク
スポンサーリンク