web-dev-qa-db-ja.com

Djangoのフィールドに制約を追加する

db.models.Modelをサブクラス化する際に、チェック/制約を追加することが不可欠な場合があります。

例えば。 start_dateend_dateEventモデルがあります。

end_date > start_dateになるように、フィールドまたはモデルに検証を追加したいと思います。

これを行うための可能な方法はいくつありますか?

少なくとも、これはModelForm検証内のmodels.Model外で実行できることを私は知っています。

しかし、フィールドとmodels.Modelにアタッチする方法は?

31
Viet

このような制約をsaveメソッドに入れません。手遅れです。そこで例外を発生させても、データを間違った方法で入力したユーザーの助けにはなりません。データが500になり、エラーなどのフォームが返されなくなるためです。

Forms/ModelFormsのcleanメソッドでこれを実際にチェックし、ValidationErrorを発生させる必要があるため、form.is_valid()はfalseを返し、フォーム内のエラーをユーザーに返送して修正することができます。

また、バージョン1.2以降、Djangoには モデル検証 があります。

次のようになります。

class Foo(models.Model):
    #  ... model stuff...
    def clean(self):
        if self.start_date > self.end_date:
            raise ValidationError('Start date is after end date')
50
stefanw

モデルのsaveメソッド内で実行します。

def save(self, *args, **kwargs):
    if(self.end_date > self.start_date):
        super(Foo, self).save(*args, **kwargs)
    else:
        raise Exception, "end_date should be greater than start_date" 
11

@stefanwが言うように、フォームのクリーンなメソッドをチェックインする方がユーザーエクスペリエンスが向上します。

値を変更する別の方法がない、または今後もそうなることがないと確信している場合は、これで十分です。ただし、それを確信できることはめったにないため、データベースの整合性が重要な場合は、フォームに加えて、次のいずれかのチェックを追加できます。

  • @ umnik700が言ったように、より簡単でデータベースに依存しない方法は、モデルのsaveメソッドにあります。これでも、データベースの他のユーザー(別のアプリ、または管理インターフェース)が一貫性のない状態を作成するのを防ぐことはできません。
  • データベースの整合性を「完全に」確認するために、データベースレベルの制約を追加できます。例えば。 RunSQL とSQLを使用して、(テストされていない)次のような移行を作成できます。

    migrations.RunSQL('ALTER TABLE app_event ADD CONSTRAINT chronology CHECK (start_date > end_date);')
    

    (未検証)。これはデータベースに依存する可能性がありますが、これはもちろん欠点です。

あなたの例では、おそらくそれは価値がなく(間違った開始/終了時間は少し奇妙に見えますが、1つの一貫性のないイベントにのみ影響します)、手動でスキーマを変更する必要はありません。ただし、一貫性が重要な場合に役立ちます。

[〜#〜] edit [〜#〜]:開始時間と終了時間の代わりに、開始時間と期間を保存することもできます。

10
Mark

今日の時点で、 postgres 9.4MS SQL Server> = 2008 の両方がSQLのチェック制約をサポートしています。これに加えて、 Django issue 11964 があり、昨日からレビューの準備ができているようです。これがDjango 2。プロジェクトに統合されることを願っています。 rapilabs/Django-db-constraints これも実装しているようです。

2
shadi