Django ChoiceField,ModelChoiceField验证

ser*_*iuz 7 django validation

我看到forms.ChoiceField使用此代码验证值:

def validate(self, value):
    """
    Validates that the input is in self.choices.
    """
    super(ChoiceField, self).validate(value)
    if value and not self.valid_value(value):
        raise ValidationError(
            self.error_messages['invalid_choice'],
            code='invalid_choice',
            params={'value': value},
        )

def valid_value(self, value):
    "Check to see if the provided value is a valid choice"
    text_value = force_text(value)
    for k, v in self.choices:
        if isinstance(v, (list, tuple)):
            # This is an optgroup, so look inside the group for options
            for k2, v2 in v:
                if value == k2 or text_value == force_text(k2):
                    return True
        else:
            if value == k or text_value == force_text(k):
                return True
    return False
Run Code Online (Sandbox Code Playgroud)

这段代码:forms.models.ModelChoiceField

def validate(self, value):
    return Field.validate(self, value)
Run Code Online (Sandbox Code Playgroud)

Q1.为什么Django使用验证来检查所选值(来自下拉列表)是否确实在选择列表中forms.ChoiceField

Q2.当Django使用Q1中的验证时,为了检查该值是否确实在选择列表中,为什么不检查所选值是否在模型记录中forms.models.ModelChoiceField

Tod*_*dor 5

验证过程从form.full_clean()开始,其中form._clean_fields()form._clean_form按此顺序执行.

现在,如果你仔细看看form._clean_fields()它做了什么,你可能会注意到它只调用field.clean(value, initial)并将结果收集到一个cleaned_data字典中.所以有趣的部分是在field.clean,让我们看看那里发生了什么:

def clean(self, value):
    """
    Validate the given value and return its "cleaned" value as an
    appropriate Python object. Raise ValidationError for any errors.
    """
    value = self.to_python(value)
    self.validate(value)
    self.run_validators(value)
    return value
Run Code Online (Sandbox Code Playgroud)

首先,我们有一个to_python电话,然后是validate完成run_validators.

因此,就ModelChoiceField何时到达.validate方法而言,您的选择已经是Model实例,这就是为什么,这种验证(来自Q2)在to_python方法中发生.

def to_python(self, value):
    if value in self.empty_values:
        return None
    try:
        key = self.to_field_name or 'pk'
        value = self.queryset.get(**{key: value})
    except (ValueError, TypeError, self.queryset.model.DoesNotExist):
        raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
    return value
Run Code Online (Sandbox Code Playgroud)