Django ChoiceField, ModelChoiceField validation

I see forms.ChoiceField using this code to check the value:

 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 

and forms.models.ModelChoiceField this code :

 def validate(self, value): return Field.validate(self, value) 

Q1. Why does Django use validation to check if the selected value (from the drop-down list) is really in the selection list for forms.ChoiceField ?

Q2. When Django uses validation from Q1 to check if the value is really in the selection list, why is it also not checking if the selected value is in the model samples for forms.models.ModelChoiceField ?

+7
django validation
source share
2 answers

The validation process begins with form.full_clean () , where you have form._clean_fields () and form._clean_form executed in this order.

Now, if you take a closer look at what form._clean_fields() does, you will probably notice that it only calls field.clean(value, initial) and collects the results in a cleaned_data dict. So, the interesting part is in field.clean , it allows you to see what happens there:

 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 

First we have a call to_python , followed by validate and ending with run_validators .

So, in terms of ModelChoiceField , when you reach the .validate method, your choice is already an instance of the model, so this validation (from Q2) happens inside 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 
+5
source share

one thing i can say for forms. ChoiceField input comes from the user's point of view, which means that the user can use the check item and enter a selection that does not appear from the backend.

but for models, some are selected directly from the backend or database

+2
source share

All Articles