Bennie
Bennie

Reputation: 509

How do I add custom validation to a Django modelForm?

I have the following Django modelform. My form is for entering in times on a timesheet, and there are start_time and end_time fields. I want to add a custom check to make sure that the start_time is before, or less than, the end_time, or else if not provide some feed back to the user if it isn't. I'm trying to create a custom clean method to do that, but i'm doing something wrong.

(snippet from models.py)

class TimesheetEntry(Model):
    WORKED='worked'
    SICK='sick'
    VACATION='vacation'
    TIME_CHOICES=(
        (WORKED,'Worked'),
        (SICK,'Sick'),
        (VACATION,'Vacation'))

    timesheet = models.ForeignKey('Timesheet', related_name='entries')
    start_time = models.DateTimeField(default=datetime.datetime.now)
    end_time = models.DateTimeField(blank=True, null=True)

(snippet from forms.py)

class TimesheetEntryForm(forms.ModelForm):
    start_time = forms.DateTimeField(widget=forms.SplitDateTimeWidget())
    end_time = forms.DateTimeField(widget=forms.SplitDateTimeWidget())
    class Meta:
        model = TimesheetEntry
        exclude = ['timesheet']

    def clean(self, *args, **kwargs):
        super(TimesheetEntryForm, self).clean(*args, **kwargs)
        if self.fields['start_time'] >= self.fields['end_time']:
            raise ValidationError("Start Time should be less than End Time")

When I submit the form(whether the start_time is less than or greater than the end_time, i strangely get one of two errors with no apparent reason why it doesn't give me the same one each time. It does not update the db, and i can repeatedly try submitting the same form with the same data over and over and will give me one of the following two errors with approximately 50% probability as to which one. I know this is a small piece of a big puzzle, but I'm hoping someone can spot an obvious error i'm making and help me figure out how to correct this.

TypeError: argument of type 'NoneType' is not iterable

-OR-

NameError: global name 'ValidationError' is not defined

it should be noted that by removing the clean() method from the method will stop the errors and allow me to input new entries(including those resulting in a negative hours total-which is the end problem i'm trying to solve)

Upvotes: 3

Views: 6367

Answers (2)

Daniel Roseman
Daniel Roseman

Reputation: 599450

Two errors: firstly, you should access self.cleaned_data['start_time'] (and end_time); and second, you need to reference forms.ValidationError.

Also, it won't hurt to do it but there is no actual need to call the super clean method.

Upvotes: 0

Joris
Joris

Reputation: 471

Regarding the NameError, simply:

from django.core.exceptions import ValidationError

One more note, instead of rewriting form fields, do the following within the form's Meta:

widgets = {
           'start_time': SplitDateTimeWidget(),
           'end_time': SplitDateTimeWidget(),
          }

Lastly, clean method should look something like this:

def clean(self):
    cleaned_data = super(TimesheetEntryForm, self).clean()
    if cleaned_data.get('start_time') >= cleaned_data.get('end_time'):
        raise ValidationError("blah blah")

Hope it helps!

Upvotes: 1

Related Questions