kieran
kieran

Reputation: 2312

Django ModelForm - conditional validation

I need to add a conditional piece of validation to my ModelForm.

Below is my Listing Model.

LISTING_TYPES = (
    ('event', 'event'),
    ('release', 'release')
)

class Listing(models.Model):
    title = models.CharField(max_length=255, verbose_name='Listing Title')
    type = models.CharField(max_length=255, choices=LISTING_TYPES, verbose_name='Listing Type')
    slug = models.SlugField(max_length=100)
    content = models.TextField(verbose_name='Listing Overview')
    competition = models.TextField()
    date_start = models.DateTimeField()
    time_start = models.CharField(max_length=255)
    date_end = models.DateTimeField()
    time_end = models.CharField(max_length=255)
    pub_date = models.DateTimeField('date published', auto_now_add=True)
    venue = models.ForeignKey(Venue)

class ListingForm(ModelForm):
    date_start = forms.DateField(input_formats=DATE_INPUT_FORMATS)
    date_end = forms.DateField(input_formats=DATE_INPUT_FORMATS)
    class Meta:
        model = Listing

Venue should only be required if type == 'event'. If type == 'release', I want venue to be required=False

How can I go about this?

Thanks

Upvotes: 1

Views: 1894

Answers (2)

Kevin Christopher Henry
Kevin Christopher Henry

Reputation: 49092

You mentioned doing ModelForm validation, but you should ask yourself if this rule is specific to creating objects with forms, or whether it is inherent in your data model itself. If it's the latter, then doing model validation makes more sense.

from django.core.exceptions import ValidationError

class Listing(models.Model):
    ...
    def clean(self):
        super(Listing, self).clean()

        if self.type == 'event' and not self.venue:
            raise ValidationError('A venue is required for events')

This will be called during ModelForm validation, so it will have the same effect there, but defining it on the model allows you to check the consistency of your data at any point with the Model.full_clean() method.

As Iain points out, you first need to allow null values for venue.

venue = models.ForeignKey(Venue, blank=True, null=True)

Upvotes: 2

Iain Shelvington
Iain Shelvington

Reputation: 32294

First Listing.venue needs to allow null values

venue = models.ForeignKey(Venue, blank=True, null=True)

Your ModelForm then needs a clean method. Something like the following

def clean(self):
    cleaned_data = super(ListingForm, self).clean()
    venue = cleaned_data.get("venue")
    type = cleaned_data.get("type")

    if type == 'event' and not venue:
        raise forms.ValidationError("A venue is required for events")

Upvotes: 4

Related Questions