Python 为什么django 的model.save() 不调用full_clean()?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4441539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't django's model.save() call full_clean()?
提问by Aaron
I'm just curious if anyone knows if there's good reason why django's orm doesn't call 'full_clean' on a model unless it is being saved as part of a model form.
我只是很好奇是否有人知道 django 的 orm 是否有充分的理由不在模型上调用“full_clean”,除非它被保存为模型表单的一部分。
Note that full_clean() will not be called automatically when you call your model's save() method. You'll need to call it manually when you want to run one-step model validation for your own manually created models. django's full clean doc
请注意,当您调用模型的 save() 方法时,不会自动调用 full_clean()。当您想为自己手动创建的模型运行一步模型验证时,您需要手动调用它。 django 的完整清洁文档
(NOTE: quote updated for Django 1.6... previous django docs had a caveat about ModelForms as well.)
(注意:为 Django 1.6 更新了报价......之前的 django 文档也有关于 ModelForms 的警告。)
Are there good reasons why people wouldn't want this behavior? I'd think if you took the time to add validation to a model, you'd want that validation run every time the model is saved.
人们不想要这种行为是否有充分的理由?我认为如果您花时间向模型添加验证,您会希望每次保存模型时都运行该验证。
I know how to get everything to work properly, I'm just looking for an explanation.
我知道如何让一切正常工作,我只是在寻找一个解释。
采纳答案by lqc
AFAIK, this is because of backwards compatibility. There are also problems with ModelForms with excluded fields, models with default values, pre_save() signals, etc.
AFAIK,这是因为向后兼容。带有排除字段的 ModelForms、带有默认值的模型、pre_save() 信号等也存在问题。
Sources you might be intrested in:
您可能感兴趣的来源:
回答by Alfred Huang
Because of the compatibility considering, the auto clean on save is not enabled in django kernel.
由于考虑兼容性,django 内核中没有启用保存时自动清理。
If we are starting a new project and want the default savemethod on Model could clean automatically, we can use the following signal to do clean before every model was saved.
如果我们正在启动一个新项目,并希望saveModel 上的默认方法可以自动清理,我们可以在保存每个模型之前使用以下信号进行清理。
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()
回答by Alfred Huang
Instead of inserting a piece of code that declares a receiver, we can use an app as INSTALLED_APPSsection in settings.py
我们可以使用应用程序作为INSTALLED_APPS部分,而不是插入一段声明接收器的代码settings.py
INSTALLED_APPS = [
# ...
'django_fullclean',
# your apps here,
]
Before that, you may need to install django-fullcleanusing PyPI:
在此之前,您可能需要django-fullclean使用 PyPI进行安装:
pip install django-fullclean
回答by M.Void
The simpliest way to call the full_cleanmethod is just to override savemethod in your model:
调用该full_clean方法的最简单方法就是save在您的model:
def save(self, *args, **kwargs):
self.full_clean()
return super(YourModel, self).save(*args, **kwargs)
回答by shacker
If you have a model that you want to ensure has at least one FK relationship, and you don't want to use null=Falsebecause that requires setting a default FK (which would be garbage data), the best way I've come up with is to add custom .clean()and .save()methods. .clean()raises the validation error, and .save()calls the clean. This way the integrity is enforced both from forms and from other calling code, the command line, and tests. Without this, there is (AFAICT) no way to write a test that ensures that a model has a FK relation to a specifically chosen (not default) other model.
如果您有一个模型要确保至少有一个 FK 关系,并且您不想使用,null=False因为这需要设置默认 FK(这将是垃圾数据),我想出的最好方法是添加自定义.clean()和.save()方法。.clean()引发验证错误,并.save()调用清洁。通过这种方式,可以从表单和其他调用代码、命令行和测试中强制执行完整性。没有这个,(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
回答by Peter Shannon
Commenting on @Alfred Huang's answer and coments on it. One might lock the pre_save hook down to an app by defining a list of classes in the current module (models.py) and checking against it in the pre_save hook:
评论@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()

