AnotherHowie
AnotherHowie

Reputation: 822

Django CreateView and validation

I'm trying to implement generic views in my Django 1.8 app, so that Django can take care of the validation/redirection loop for me.

I've 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 validated 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 that the admin interface would use the validators when I added a Customer, but it doesn't)

For the actual app, I've created a ModelForm for the Customer class:

class CustomerForm(ModelForm):

    class Meta:
            model = Customer
            fields = ['custid', 'customer_shortcode', 'description']

and a 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 I enter invalid data in the generated form.

As far as I can follow from the docs, I should only need to override clean() or clean_xxx() on the ModelForm for additional validation, not for this, but it's really unclear. I'd like to keep the knowledge about what constitutes a valid value in as few places as possible - which the validator on the ModelField would do.

What is missing here? I suspect I'm getting confused between model validation and form validation...

Upvotes: 3

Views: 2402

Answers (1)

Andrei Avram
Andrei Avram

Reputation: 948

TL;DR: when specifying this kind of validators in model field definitions, you should pass instances rather than classes (validators.CIDValidator() instead of validators.CIDValidator).

Longer explanation

Django validators need to be callables. Trying to call the class you are passing now will go through python's creation sequence for an instance, calling __new__ and __init__, and it would return an instance of that class - but it won't do anything in terms of validating the field value.

The Django validators you are subclassing also have a __call__ method, that is run when you try to call an instance of that class, and it takes care of validating and raising ValidationErrors

Upvotes: 3

Related Questions