Wednesday, May 10, 2017

Django ChoiceField, ModelChoiceField validation

Leave a Comment

I see that forms.ChoiceField is using this code to validate 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 Django uses validation to check if the selected value (from dropdown) is indeed in the choice list for forms.ChoiceField?

Q2. When Django uses the validation from Q1, to check if the value is indeed in the choice list, why does not also check if the selected value is in the model records for forms.models.ModelChoiceField?

2 Answers

Answers 1

The validation process starts from 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() do, you will probably notice that it only calls field.clean(value, initial) and collects the results into a cleaned_data dict. So the interesting part is at field.clean, lets 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 to_python call, followed by validate and finishing with run_validators.

So in terms of ModelChoiceField when you reach the .validate method, your choice is already a Model instance, thats why, this kind of validation (from Q2) is happening inside the to_python method.

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 

Answers 2

one thing i can say is for forms.ChoiceField the input are coming from the user perspective means a user can use inspect element and enter a choice which doesnt appear from the backend .

but for models one the choices are directly coming from the backend or the database

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment