我不确定如何在模型的保存方法中正确引发验证错误,并向用户发回明确的消息。
基本上我想知道“if”的每个部分应该如何结束,我想要引发错误的部分 以及它实际存储的那个:
def save(self, *args, **kwargs):
if not good_enough_to_be_saved:
raise ValidationError
else:
super(Model, self).save(*args, **kwargs)
然后我想知道该怎么做才能发送一个验证错误,该错误向用户说明错误,就像Django自动返回的那样,例如,如果某个值不唯一。 我正在使用(ModelForm)并从模型中调整所有内容。
答案 0 :(得分:45)
大多数Django观看例如Django管理员将无法处理保存方法中的验证错误,因此您的用户将收到500个错误。
您应该对模型表单或模型进行验证,并在那里引发ValidationError
。只有当模型表单数据“足以保存”时才调用save()
。
答案 1 :(得分:24)
巴斯蒂安,我向你解释我的代码模板,我希望这对你有所帮助:
自django 1.2 it is able to write validation code on model以来。当我们使用modelforms时,在表单验证时调用instance.full_clean()。
在每个模型中,我使用自定义函数覆盖clean()
方法(此方法在modelform验证时自动从full_clean()调用):
from django.db import models
class Issue(models.Model):
....
def clean(self):
rules.Issue_clean(self) #<-- custom function invocation
from issues import rules
rules.connect()
然后在rules.py
文件中我写了商务规则。我还将pre_save()
连接到我的自定义函数,以防止保存状态错误的模型:
来自issues.models导入问题
def connect():
from django.db.models.signals import post_save, pre_save, pre_delete
#issues
pre_save.connect(Issue_pre_save, sender = Incidencia )
post_save.connect(Issue_post_save, sender = Incidencia )
pre_delete.connect(Issue_pre_delete, sender= Incidencia)
def Incidencia_clean( instance ): #<-- custom function
import datetime as dt
errors = {}
#dia i hora sempre informats
if not instance.dia_incidencia: #<-- business rules
errors.setdefault('dia_incidencia',[]).append(u'Data missing: ...')
#dia i hora sempre informats
if not instance.franja_incidencia:
errors.setdefault('franja_incidencia',[]).append(u'Falten Dades: ...')
#Només es poden posar incidències més ennlà de 7 dies
if instance.dia_incidencia < ( dt.date.today() + dt.timedelta( days = -7) ):
errors.setdefault('dia_incidencia 1',[]).append(u'''blah blah error desc)''')
#No incidències al futur.
if instance.getDate() > datetime.now():
errors.setdefault('dia_incidencia 2',[]).append(u'''Encara no pots ....''')
...
if len( errors ) > 0:
raise ValidationError(errors) #<-- raising errors
def Issue_pre_save(sender, instance, **kwargs):
instance.clean() #<-- custom function invocation
然后,modelform调用模型的clean方法和我的custon函数检查正确的状态或引发由模型表单处理的错误。
为了在表单上显示错误,您应该将其包含在表单模板中:
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
{{error}}
{% endfor %}
{% endif %}
原因是模型验证错误ara绑定到non_field_errors错误字典条目。
当您从表单中保存或删除模型时,您应该记住可能会引发错误:
try:
issue.delete()
except ValidationError, e:
import itertools
errors = list( itertools.chain( *e.message_dict.values() ) )
此外,您可以在没有模型的情况下向表单字典添加错误:
try:
#provoco els errors per mostrar-los igualment al formulari.
issue.clean()
except ValidationError, e:
form._errors = {}
for _, v in e.message_dict.items():
form._errors.setdefault(NON_FIELD_ERRORS, []).extend( v )
请记住,此代码不是在save()方法上执行的:请注意,调用模型的save()方法时,不会自动调用full_clean(),也不会因模型化验证而自动调用。然后,您可以在 no modelforms :
上向表单字典添加错误 try:
#provoco els errors per mostrar-los igualment al formulari.
issue.clean()
except ValidationError, e:
form._errors = {}
for _, v in e.message_dict.items():
form._errors.setdefault(NON_FIELD_ERRORS, []).extend( v )
答案 2 :(得分:2)
确保也导入ValidationError
from django.core.exceptions import ValidationError
答案 3 :(得分:1)
def clean(self):
raise ValidationError("Validation Error")
def save(self, *args, **kwargs):
if some condition:
#do something here
else:
self.full_clean()
super(ClassName, self).save(*args, **kwargs)
答案 4 :(得分:0)
我认为这是针对Django 1.2+的更清晰的方法
在表单中,它将被引发为non_field_error,在其他情况下,例如DRF,您将需要检查此案例手册,因为它将是500错误。
class BaseModelExt(models.Model):
is_cleaned = False
def clean(self):
# check validation rules here
self.is_cleaned = True
def save(self, *args, **kwargs):
if not self.is_cleaned:
self.clean()
super().save(*args, **kwargs)
答案 5 :(得分:0)
在 Django 文档中,他们在 .save 方法中引发了 ValueError,它可能对您有用。 https://docs.djangoproject.com/en/3.1/ref/models/instances/
答案 6 :(得分:0)
如果要对模型进行验证,可以在模型上使用 clean()
或 clean_fields
方法。这些在执行 save()
之前由 django 调用,并以用户友好的方式处理验证错误 - django docs here。
答案 7 :(得分:-1)
大多数情况下,您只能在模型中使用clean
方法,但是内置auth.User
模型不一定具有该选项。通过此解决方案,您可以为clean
模型创建auth.User
方法,以使ValidationError
传播到调用clean方法的表单(包括管理表单)。 / p>
如果有人尝试创建或编辑auth.User
实例以使其具有与现有auth.User
实例相同的电子邮件地址,则以下示例将引发错误。 免责声明,如果您要向新用户展示注册表单,则不希望您的验证错误像我下面那样提示用户名。
from django.contrib.auth.models import User
from django.forms import ValidationError as FormValidationError
def clean_user_email(self):
instance = self
super(User, self).clean()
if instance.email:
if User.objects.filter(id=instance.id, email=instance.email).exists():
pass # email was not modified
elif User.objects.filter(email=instance.email).exists():
other_users = [*User.objects.filter(email=instance.email).values_list('username', flat=True)]
raise FormValidationError(f'At least one other user already has this email address: '
f'{", ".join(other_users)}'
, code='invalid')
# assign the above function to the User.clean method
User.add_to_class("clean", clean_user_email)
我将其放在my_app.models
的底部,但是只要您将其粘贴在有问题的表单之前已加载的位置,我相信它会起作用。