Django Modelのフィールド間でチェック(例えば”開始日”と”終了日”の前後関係)

例えばタスクというModelを作るとして、
以下のように、タスク名称と、開始日、完了期日、完了日という3つの日付フィールドをつけたとする。

from django.db import models

class Task(models.Model):
    def __str__(self):
        return self.title
    title = models.CharField(max_length=128)
    start_at = models.DateField('From')
    due_at =  models.DateField('Due',blank=True,null=True)
    end_at = models.DateField('To',blank=True,null=True)

さて、タスク登録する画面でも作ろうかってなると「開始日と終了日を逆にしたらエラーになるようにしたいな」と思うわけで、Djangoだとどういうやりようがあるのかな、と思ってネットを調べたら

① saveメソッドをオーバーライド
② MetaのConstraintsを使う
③ formのvalidationを使う

くらいの方法が見つかった。

結論は、①が一番よさそうに見えたのでこれで行くことにする。こうしてしまう。

from django.db import models

class Task(models.Model):
    def __str__(self):
        return self.title
    title = models.CharField(max_length=128)
    start_at = models.DateField('From')
    due_at =  models.DateField('Due',blank=True,null=True)
    end_at = models.DateField('To',blank=True,null=True)

    def save(self, *args, **kwargs):
        if ( (self.dueat is not None) and (self.start_at > self.due_at) ):
            raise ValidationError("Due date is before Start Date.")

        if ( (self.endat is not None) and (self.start_at > self.end_at) ):
            raise ValidationError("End date is before Start Date.")

        super(Task, self).save(*args, **kwargs)

②は、Django公式のガイドにも何やかや書いてあるんだけど、多分今回やりたいことがそもそもできない。テストもしてないけど、散々頑張ってできなかったっていうオチが何となく予想される。

③はたぶんできるけど、どうもDjangoのFormはあまり信用していなくて細かい使い方がわからないし、先々APIとかバッチ処理とか書いて、直接ModelのSaveとか叩かせたりしたときに効かないだろうから、イヤなのでやめた。ドキュメントもななめ読みしただけでも理解大変そう。

Modelによるデータの保存にsaveメソッド通らないことなんてあるのかな。多分ないからやっぱり①が確実かな、というのがいったん結論。

Leave a Comment

Your email address will not be published. Required fields are marked *