174

モデルフォームの一部として保存されていない限り、djangoのormがモデルで「full_clean」を呼び出さない正当な理由があるかどうかを誰かが知っているかどうかだけ知りたいです。

モデルのsave()メソッドを呼び出すときに、full_clean()が自動的に呼び出されないことに注意してください。手動で作成した独自のモデルに対してワンステップのモデル検証を実行する場合は、手動で呼び出す必要があります。 djangoの完全にクリーンなドキュメント

(注:引用はDjango 1.6用に更新されました...以前のdjangoドキュメントにはModelFormsについても警告がありました。)

人々がこの行動を望まない理由はありますか?モデルに検証を追加するのに時間がかかった場合は、モデルが保存されるたびに検証を実行する必要があると思います。

私はすべてを正しく機能させる方法を知っています、私はただ説明を探しています。

4

7 に答える 7

64

AFAIK、これは下位互換性のためです。除外されたフィールドを持つModelForms、デフォルト値を持つモデル、pre_save()シグナルなどにも問題があります。

あなたが興味を持っているかもしれない情報源:

于 2010-12-14T16:47:58.353 に答える
34

互換性を考慮しているため、保存時の自動クリーンアップはdjangoカーネルでは有効になっていません。

新しいプロジェクトを開始していてsave、Modelのデフォルトのメソッドを自動的にクリーンアップできるようにしたい場合は、次のシグナルを使用して、すべてのモデルが保存される前にクリーンアップを実行できます。

from django.dispatch import receiver
from django.db.models.signals import pre_save, post_save

@receiver(pre_save)
def pre_save_handler(sender, instance, *args, **kwargs):
    instance.full_clean()
于 2015-09-07T05:56:38.870 に答える
20

メソッドを呼び出す最も簡単な方法は、モデルfull_cleanのメソッドをオーバーライドすることです。save

class YourModel(models.Model):
    ...  
    
    def save(self, *args, **kwargs):
        self.full_clean()
        return super(YourModel, self).save(*args, **kwargs)
于 2016-08-12T09:57:44.020 に答える
3

受信者を宣言するコードを挿入する代わりに、アプリをINSTALLED_APPSセクションとして使用できますsettings.py

INSTALLED_APPS = [
    # ...
    'django_fullclean',
    # your apps here,
]

django-fullcleanその前に、 PyPIを使用してインストールする必要がある場合があります。

pip install django-fullclean
于 2016-06-14T22:37:12.757 に答える
3

@AlfredHuangの回答にコメントしてコメントします。現在のモジュール(models.py)でクラスのリストを定義し、pre_saveフックでそれをチェックすることで、pre_saveフックをアプリにロックダウンすることができます。

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

@receiver(pre_save)
def pre_save_handler(sender, instance, **kwargs):
    if type(instance) in CUSTOM_CLASSES:
        instance.full_clean()
于 2019-10-29T03:58:33.400 に答える
2

少なくとも1つのFK関係があることを確認したいモデルがありnull=False、デフォルトのFK(ガベージデータ)を設定する必要があるために使用したくない場合、私が思いついた最善の方法はカスタム.clean().save()メソッドを追加します。.clean()検証エラーを発生させ.save()、クリーンを呼び出します。このようにして、フォームと他の呼び出しコード、コマンドライン、およびテストの両方から整合性が適用されます。これがないと、モデルが特別に選択された(デフォルトではない)他のモデルとFK関係にあることを確認するテストを作成する方法が(AFAICT)ありません。

class Payer(models.Model):

    name = models.CharField(blank=True, max_length=100)
    # Nullable, but will enforce FK in clean/save:
    payer_group = models.ForeignKey(PayerGroup, null=True, blank=True,)

    def clean(self):
        # Ensure every Payer is in a PayerGroup (but only via forms)
        if not self.payer_group:
            raise ValidationError(
                {'payer_group': 'Each Payer must belong to a PayerGroup.'})

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

    def __str__(self):
        return self.name
于 2017-09-12T17:34:00.993 に答える
0

pre_saveモデルの検証を常に確実にしたい場合は、グローバルシグナルが適切に機能します。ただし、現在のバージョン(3.1.x)ではDjangoの認証に問題が発生し、使用している他のアプリのモデルに問題が発生する可能性があります。

@Peter Shannonの回答を詳しく説明すると、このバージョンは、実行するモジュール内のモデルのみを検証し、「生の」保存による検証をスキップして、重複信号dispatch_uidを回避するためにを追加します。

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-03-01T19:35:51.730 に答える