model fieldsの検証はdjangoのどこに行くべきですか?
少なくとも2つの選択肢を指定できます。モデルのオーバーロードされた.save()メソッドまたはmodels.Fieldサブクラスの.to_python()メソッド(これが機能するには、カスタムフィールドを記述する必要があることは明らかです)。
可能なユースケース:
モデルにはクラスレベルの属性empty_strings_allowed
もあります。フィールドの基本クラスの定義と派生クラスはそれを上手くオーバーライドしますが、データベースレベルに影響を与えないようです。つまり、モデルを構築できます空の文字列フィールドを使用して、データベースに保存します。私は避けたい(はい、それは必要です)。
可能な実装は
フィールドレベルで:
class CustomField(models.CharField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
if not value:
raise IntegrityError(_('Empty string not allowed'))
return models.CharField.to_python(self, value)
モデルレベルで:
class MyModel(models.Model)
FIELD1_CHOICES = ['foo', 'bar', 'baz']
field1 = models.CharField(max_length=255,
choices=[(item,item) for item in FIELD1_CHOICES])
def save(self, force_insert=False, force_update=False):
if self.field1 not in MyModel.FIELD1_CHOICES:
raise IntegrityError(_('Invalid value of field1'))
# this can, of course, be made more generic
models.Model.save(self, force_insert, force_update)
おそらく、私は何かを見逃していますが、これはより簡単に(そしてよりきれいに)できますか?
Djangoには、バージョン1.2以降の モデル検証 システムがあります。
コメントでは、sebpiqは「OK、モデル検証を配置する場所があります... ModelFormを使用している場合にのみ実行されることを除いて! 、あなたは何をすべきですか?full_cleanをどこで呼び出しますか?」
Pythonレベルの検証では、検証がdbレベルで尊重されるようにすることはできません。最も近いのは、おそらくオーバーライドされたsave
メソッドで_full_clean
_を呼び出すことです。これは、そのsaveメソッドを呼び出すすべての人がValidationError
をキャッチして処理する準備ができていることを意味するため、デフォルトでは行われません。
ただし、これを行っても、誰かがqueryset.update()
を使用してモデルインスタンスを一括で更新できます。これにより、この検証がバイパスされます。 Djangoは、更新されたすべてのオブジェクトでPythonレベルの検証を実行できる、合理的に効率的なqueryset.update()
を実装できません。
DBレベルの整合性を実際に保証する唯一の方法は、DBレベルの制約を使用することです。 ORMを使用して検証を行うには、検証の実施時期(および検証の失敗の処理)をアプリコードの作成者が認識する必要があります。
これが、モデル検証がデフォルトでModelForm
でのみ強制される理由です-ModelFormではValidationError
を処理する明白な方法が既にあるためです。
これが欲しいと思う->
from Django.db.models.signals import pre_save
def validate_model(sender, **kwargs):
if 'raw' in kwargs and not kwargs['raw']:
kwargs['instance'].full_clean()
pre_save.connect(validate_model, dispatch_uid='validate_models')
これの根本的な問題は、検証がモデルで行われるべきであるということです。これは、かなり以前からDjango(devメーリングリストでフォームモデルを認識した検証を検索)で議論されています。
それはトランクには当たりませんが、Malcolmの "貧しい人のモデル検証ソリューション" は、おそらく自分自身の繰り返しを避けるための最もクリーンなソリューションです。
私があなたを「明確に」理解している場合-to_pythonの代わりにget_db_prep_save関数をオーバーライドする必要があります