https://docs.djangoproject.com/en/1.10/ref/forms/validation/
run_validators()
在表单子类clean()
之前运行的状态。
我的模型看起来像:
def validate_ascii(value):
try:
value.encode('ascii')
except UnicodeEncodeError:
raise ValidationError("Contains non-ascii characters")
class Keyword(models.Model):
name = models.CharField(max_length=50, unique=True, validators=[validate_ascii])
在我的表单clean()
方法
class KeywordAdminForm(ModelForm):
class Meta:
model = Keyword
def clean(self):
import pdb; pdb.set_trace()
cleaned_data = super(KeywordAdminForm, self).clean()
import pdb; pdb.set_trace()
return super(KeywordAdminForm, self).clean()
之后,运行表单中每个字段的验证器。这会导致问题,因为我的clean方法假定每个字段都先运行validator
并崩溃。
为什么我的表单的clean()
方法在字段上的验证器之前运行?
答案 0 :(得分:3)
更改您的表单clean()
方法,以便在执行其余验证之前先调用cleaned_data = super(KeywordAdminForm, self).clean()
。 This is how the docs recommend you do it
This section of the docs对您的问题有解释。
模型验证(Model.full_clean())是从内部触发的 表单验证步骤,在调用表单的clean()方法之后。
这表明您不能依赖干净方法中的任何模型验证
答案 1 :(得分:0)
根据文档的“ Validation on a ModelForm”段:
验证ModelForm涉及两个主要步骤:
- 验证表单
- 验证模型实例
这定义了两层完全不同的验证层,一层在模型层,一层在表单层。
因此,期望这些验证层以某种方式相关显然是错误的。
但是,有一个合理的解决方案,如同一章的"Overriding the Default Fields“段落中所述:
如果您想指定字段的验证者,可以通过定义 声明性地设置字段并设置其验证器参数。
您的示例可能变成:
from django.forms import CharField, ModelForm
from myapp.models import Keyword
class KeywordAdminForm(ModelForm):
slug = CharField(max_length=50, validators=[validate_ascii])
class Meta:
model = Keyword
fields = '__all__'
请记住,但请阅读此示例后面的绿色“注释”,其中指出:
类似地,以声明方式定义的字段不会绘制其属性 如来自相应模型的
max_length
或required
。如果你想 要维持模型中指定的行为,您必须设置 声明表单字段时明确地提供相关参数。
或者,您可以执行以下操作:
from django.forms import CharField, ModelForm
from myapp.models import Keyword, validate_ascii
class KeywordAdminForm(ModelForm):
def clean_slug(self):
slug = self.cleaned_data.get('slug')
validate_ascii(slug)
return slug
def clean(self):
cleaned_data = super().clean()
if self.errors:
return cleaned_data
...
return cleaned_data
class Meta:
model = Keyword
fields = '__all__'
上面的代码之所以有效,是因为它可能在ValidationError
之前调用的clean_<field>()
内引发一个clean()
。