Django CreateView and validation
I am trying to implement shared views in my Django 1.8 application so that Django can take care of the validation / redirect loop for me.
I created a model:
class Customer(models.Model):
custid = models.CharField(max_length=4, verbose_name='CID (4 alphanumeric uppercase)', validators=[validators.CIDValidator])
customer_shortcode = models.CharField(max_length=7, verbose_name='Customer Code (7 chars, uppercase, no spaces)', validators=[validators.ShortnameValidator])
description = models.CharField(max_length=30, blank=True)
and defined a validator for each of my two approved fields:
class CIDValidator(RegexValidator):
regex = r'^[A-Z0-9]{4}$'
message = 'CID is a 4-character uppercase alphanumeric value'
class ShortnameValidator(RegexValidator):
regex = r'^[A-Z0-9_]{1,7}$'
message = 'Shortname should be uppercase, no spaces, alphanumeric'
(At this point, I expected the admin interface to use validators when adding a Client, but this is not the case)
For a real application, I created a ModelForm for the Customer class:
class CustomerForm(ModelForm):
class Meta:
model = Customer
fields = ['custid', 'customer_shortcode', 'description']
and the View class inherited from CreateView:
class CustomerCreateView(CreateView):
model = Customer
form_class = CustomerForm
def get_success_url(self):
return reverse('customer_list')
And I still don't get validation errors when entering invalid data in the generated form.
As far as I can follow from the docs, I only need to override clean () or clean_xxx () in the ModelForm for additional validation, but not for that, but this is really unclear. I would like to keep the information about what the valid value is in as few places as possible, which is what the validator on the ModelField does.
What's missing here? I suspect I am confused between model validation and form validation ...
source to share
TL; DR: When specifying these kind of validators in model field definitions, you must pass in instances, not classes ( validators.CIDValidator()
instead of validators.CIDValidator
).
Longer explanation
Django validators must be callers . Trying to call the class you are currently going through will go through the python instantiation sequence, calling __new__
and __init__
, and it will return an instance of that class, but it will do nothing in terms of validating the field value.
The Django subcategories that you subclass also have a method __call__
that gets triggered when you try to invoke an instance of that class, and it takes care of checking and promoting ValidationError
s
source to share