Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clean() method in model and field validation

Tags:

I have a problem with a model's clean() method and basic field validation. here's my model and the clean() method.

class Trial(models.Model):

    trial_start = DurationField()
    movement_start = DurationField()
    trial_stop = DurationField()


    def clean(self):
        from django.core.exceptions import ValidationError
        if not (self.movement_start >= self.trial_start):
            raise ValidationError('movement start must be >= trial start')
        if not (self.trial_stop >= self.movement_start):
            raise ValidationError('trial stop must be >= movement start')
        if not (self.trial_stop > self.trial_start):
            raise ValidationError('trial stop must be > trial start')

My clean() method checks whether certain values are in the correct range. If the user forget to fill out a field, e.g. movement_start, then I get an error:

can't compare datetime.timedelta to NoneType

I'm surprised that I get this error, since the original clean() function should be catching that missing entry (after all movement_start is a required field). So how can I the basic checking for missing values, and my custom check whether values are in certain ranges? Can this be done with model's clean() method, or do I need to use Forms?

EDIT1 to make it more clear: trial_start, movement_start and trial_stop are all required fields. I need to write a clean() method which first checks that all three fields have been filled out, and then, check whether the values are in a certain range.

The following code for example DOES NOT work, since trial_start might be empty. I want to avoid having to check for the existence of each field - django should do that for me.

class TrialForm(ModelForm):

    class Meta:
        model = Trial

    def clean_movement_start(self):
        movement_start = self.cleaned_data["movement_start"]
        trial_start = self.cleaned_data["trial_start"]
        if not (movement_start >= trial_start):
            raise forms.ValidationError('movement start must be >= trial start')
        return self.cleaned_data["movement_start"] 

EDIT2 The reason that I wanted to add this check to the model's clean() method is that objects that are created on the python shell, will automatically be checked for correct values. A form will be fine for views, but I need the value check also for the shell.

like image 926
memyself Avatar asked Sep 05 '12 09:09

memyself


People also ask

What is the use of cleaned data in Django?

cleaned_data is where all validated fields are stored.

What can be used to validate all model fields if any field is to be exempted from validation provide it in the exclude parameter?

clean_fields() method documentation: This method will validate all fields on your model. The optional exclude argument lets you provide a list of field names to exclude from validation. It will raise a ValidationError if any fields fail validation.

What is field validation?

Field validation is an automated process of ascertaining that each field contains the correct value before the form is accepted. The concept is straightforward.

How do you remove this field is required Django?

If yes try to disable this behavior, set the novalidate attribute on the form tag As <form action="{% url 'new_page' %}", method="POST" novalidate> in your html file.


1 Answers

I guess that's the way to go:

class TrialForm(ModelForm):

    class Meta:
        model = Trial

    def clean(self):
        data = self.cleaned_data
        if not ('movement_start' in data.keys() and 'trial_start' in data.keys()  and 'trial_stop' in data.keys()):
            raise forms.ValidationError("Please fill out missing fields.")

        trial_start = data['trial_start']
        movement_start = data['movement_start']
        trial_stop = data['trial_stop']

        if not (movement_start >= trial_start):
            raise forms.ValidationError('movement start must be >= trial start')

        if not (trial_stop >= movement_start):
            raise forms.ValidationError('trial stop must be >= movement start')

        if not (trial_stop > trial_start):
            raise forms.ValidationError('trial stop must be > trial start')

        return data

EDIT the downside of this approach is, that value checking will only work if I create objects through the form. Objects that are created on the python shell won't be checked.

like image 141
memyself Avatar answered Oct 13 '22 21:10

memyself