为什么 django 的 model. save ()不调用 full _ clean () ?

我只是好奇是否有人知道为什么 django 的 orm 不在模型上调用“ full _ clean”,除非它被保存为模型表单的一部分。

请注意,在调用模型的 save ()方法时,full _ clean ()不会被自动调用。当您想为自己手动创建的模型运行一步模型验证时,需要手动调用它。 姜戈是清白的,医生

(注意: 引用 Django 1.6的更新... ... 以前的 Django docs 对 ModelForms 也有一个警告。)

人们不希望这种行为有什么好的理由吗?我认为,如果您花时间将验证添加到模型中,那么您会希望每次保存模型时都运行验证。

我知道怎么让一切正常运转,我只是在寻找一个解释。

38211 次浏览

AFAIK,这是因为向后兼容性。ModelForms 还存在排除字段、缺省值模型、 pre _ save ()信号等问题。

你可能感兴趣的资料来源:

由于兼容性的考虑,django 内核中没有启用自动清除保存。

如果我们正在开始一个新的项目,并希望模型上的默认 save方法可以自动清理,我们可以使用以下信号做清理之前,每个模型被保存。

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()

我们可以在 settings.py中使用应用程序作为 INSTALLED_APPS部分,而不是插入一段声明接收器的代码

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

在此之前,您可能需要使用 PyPI 安装 django-fullclean:

pip install django-fullclean

调用 full_clean方法的最简单方法就是重写模型中的 save方法:

class YourModel(models.Model):
...
    

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

如果你有一个模型,你想确保至少有一个 FK 关系,你不想使用 null=False,因为这需要设置一个默认的 FK (这将是垃圾数据) ,最好的方法我想到的是添加自定义 .clean().save()方法。.clean()引发验证错误,.save()调用 clean。通过这种方式,可以从表单和其他调用代码、命令行和测试中强制执行完整性。如果没有这个,就没有办法编写一个测试来确保一个模型与一个特定选择的(不是默认的)其他模型有一个 FK 关系。

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

评论@Alfred Huang 的回答和评论。人们可以通过在当前模块中定义一个类列表(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()

如果您希望始终确保模型验证,那么全局 pre_save信号可以很好地工作。然而,它会遇到与 Django 在当前版本(3.1.x)的认证问题,并可能导致与模型的问题,从其他应用程序您使用。

详细说明@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')