问题:django的model.save()为什么不调用full_clean()?
我只是好奇是否有人知道,除非有理由将django的orm不保存在模型中,否则它不会在模型上调用“ full_clean”。
请注意,当您调用模型的save()方法时,不会自动调用full_clean()。若要为自己创建的模型运行一步模型验证,则需要手动调用它。 django的完整档案
(注意:报价已针对Django 1.6更新…之前的django文档也对ModelForms提出了警告。)
人们为什么不希望这种行为有充分的理由?我想如果您花时间向模型添加验证,则希望每次保存模型时都运行验证。
我知道如何使一切正常工作,我只是在寻找一种解释。
回答 0
AFAIK,这是因为向后兼容。带有排除字段的ModelForms,具有默认值的模型,pre_save()信号等也存在问题。
您可能感兴趣的资源:
回答 1
由于考虑到兼容性,因此在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()
回答 2
调用该full_clean
方法的最简单方法是save
在您的方法中覆盖该方法model
:
def save(self, *args, **kwargs):
self.full_clean()
return super(YourModel, self).save(*args, **kwargs)
回答 3
除了插入件的代码,声明了一个接收器的,我们可以使用一个应用程序如INSTALLED_APPS
在节settings.py
INSTALLED_APPS = [
# ...
'django_fullclean',
# your apps here,
]
在此之前,您可能需要django-fullclean
使用PyPI 安装:
pip install django-fullclean
回答 4
如果您要确保具有至少一个FK关系的模型,并且不想使用该模型,null=False
因为这需要设置默认FK(这将是垃圾数据),那么我想出的最好方法是添加自定义.clean()
和.save()
方法。.clean()
引发验证错误,并.save()
调用clean。这样,可以从表单以及其他调用代码,命令行和测试中强制执行完整性。没有这个,就无法(AFAICT)编写测试来确保模型与特定选择的(非默认)其他模型具有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
回答 5
评论@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()