37

私が理解しているように、Djangoアプリケーションを作成すると、データはフォームによって検証されてから、モデルインスタンスに挿入され、データベースに書き込まれます。しかし、データモデルレイヤーに追加の保護レイヤーを作成したい場合、現在の「ベストプラクティス」の下で行ったことはありますか?レビューアの名前を省略したり、空白のままにしたりできないようにしています。ここで行ったように、カスタム検証を「clean」メソッドに入れてから、「save」で「full_clean」を呼び出して「clean」を呼び出す必要がありますか?そうでない場合、推奨される方法は何ですか?ありがとうございます。

class Reviewer(models.Model):
    name = models.CharField(max_length=128, default=None)

    def clean(self, *args, **kwargs):
        if self.name == '':
            raise ValidationError('Reviewer name cannot be blank')
        super(Reviewer, self).clean(*args, **kwargs)

    def full_clean(self, *args, **kwargs):
        return self.clean(*args, **kwargs)

    def save(self, *args, **kwargs):
        self.full_clean()
        super(Reviewer, self).save(*args, **kwargs)
4

4 に答える 4

45

まず、これまでのようにオーバーライドfull_cleanしないでください。full_cleanのdjangoドキュメントから:

Model.full_clean(exclude=None)
このメソッドは、、、およびをこの順序で呼び出し、3Model.clean_fields()つのステージすべてからのエラーを含む属性を持つを発生させます。Model.clean()Model.validate_unique()ValidationErrormessage_dict

したがって、full_cleanメソッドはすでにを呼び出しますcleanが、オーバーライドすることで、他の2つのメソッドを呼び出さないようにしています。

full_clean次に、メソッドの呼び出しsaveはトレードオフです。full_cleanモデルフォームが検証されるときに、たとえばDjangoadminですでに呼び出されていることに注意してください。したがって、メソッドを呼び出すfull_cleanと、saveメソッドは2回実行されます。

通常、saveメソッドで検証エラーが発生することは想定されていません。誰かが呼び出しsaveて、結果のエラーをキャッチしない可能性があります。full_cleanただし、 saveメソッド自体でチェックを行うのではなく、呼び出すのが好きです。このアプローチにより、モデルフォームが最初に問題をキャッチできます。

最後に、cleanメソッドは機能しますが、実際にはモデルフィールド自体でサンプルケースを処理できます。あなたCharField

name = models.CharField(max_length=128)

このblankオプションはデフォルトでFalseになります。フィールドが空白の場合、ValidationErrorを実行するとaが発生しますfull_clean。を入れdefault=NoneCharFieldも害はありませんが、実際にNone値として許可しない場合は少し混乱します。

于 2012-10-18T01:07:18.347 に答える
7

Alasdairの答えを考え、さらに読んだ後、私の感覚は、Djangoのモデルは、私がやろうとしているように、モデルのみに基づいて検証されるように設計されていなかったということです。このような検証は実行できますが、コストがかかり、意図しない方法で検証方法を使用する必要があります。

代わりに、モデルフィールド宣言に直接入力できる制約(「unique = True」など)以外の制約は、FormまたはModelForm検証の一部として実行されることになっていると思います。他の手段(Pythonインタープリター内での作業中にORMを介するなど)を介してプロジェクトのデータベースに無効なデータを入力しないようにする場合は、データベース自体の内部で検証を行う必要があります。したがって、検証は次の3つのレベルで実装できます。1)まず、データベースのDDLを介してすべての制約とトリガーを実装します。2)モデルフィールドで使用可能な制約を実装します(例: "unique = True")。3)フォームおよびModelForms内のデータベースレベルの制約とトリガーを反映する他のすべての制約と検証を実装します。このアプローチでは、フォーム検証エラーは、ユーザーに再表示できます。また、プログラマーがORMを介してデータベースと直接対話している場合、プログラマーはデータベースの例外を直接確認します。

誰か考えますか?

于 2012-10-18T22:48:10.593 に答える
6

モデルで事前保存信号をキャプチャすると、クリーンが自動的に呼び出されます。

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')
于 2016-04-26T02:04:24.530 に答える
0

@Kevin Parkerの回答に感謝します、非常に役に立ちました!

定義したモデル以外のモデルをアプリに含めるのが一般的であるため、この動作を独自のモデルまたは必要に応じて特定のアプリ/モジュールにのみスコープするために使用できる変更バージョンを次に示します。

from django.db.models.signals import pre_save
import inspect
import sys

MODELS = [obj for name, obj in
    inspect.getmembers(sys.modules[__name__], inspect.isclass)]

def validate_model(sender, instance, **kwargs):
    if 'raw' in kwargs and not kwargs['raw']:
        if type(instance) in MODELS:
            instance.full_clean()

pre_save.connect(validate_model, dispatch_uid='validate_models')

このコードは、実行されるモジュール内で定義されたすべてのモデルに対して実行されますが、スコープをより厳密に設定したり、必要に応じてモジュール/アプリのセットに調整したりできます。

于 2021-02-27T00:05:00.857 に答える