Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Form Validation on Class Based View

I have a very simple Class Based View:

In views.py:

class IncidentEdit(UpdateView):
    model=Incident
    fields = visible_field_list
    sucess_url = '/status'

works fine as-is. I have associated CreateView, DeleteView, etc. I can create edit and delete records. Now to fine-tune the project, I need to add field validation.

My question: Where do I put basic validation code when I have based the view on the 'model=' rather than 'form='?

I could change everything to use form based views, but the whole idea was to keep it simple and it works, I just don't have the form validation except for basic 'Field Required' type validation that was defined in the model declaration.

For example, I need to make sure that one field equals the sum of two other fields. Like,

ClassRoomTotal = NumBoys + NumGirls

and raise a validation error for the ClassRoomTotal field if the sum doesn't match the total.

Thanks in advance.
I know it is a simple answer.

Suggestions like, "You can't do that, you have to use form=IncidentForm and define a form class." would help.

like image 407
Kendall Avatar asked May 01 '15 04:05

Kendall


2 Answers

class IncidentEdit(UpdateView):

    ...

    def form_valid(self, form):
        if form.cleaned_data['email'] in \
        [i.email for i in Incident.objects.exclude(id=get_object().id)]:
            # Assume incident have email and it should be unique !!
            form.add_error('email', 'Incident with this email already exist')
            return self.form_invalid(form)
        return super(IncidentEdit, self).form_valid(form)

Also, hope this link would be useful. http://ccbv.co.uk/projects/Django/1.7/django.views.generic.edit/UpdateView/

like image 62
Vinayak Kaniyarakkal Avatar answered Oct 23 '22 09:10

Vinayak Kaniyarakkal


Well,

you can't do that, you have to use form = IncidentForm

or at least it is the simplest solution.

Note that you have to use form_class = IncidentForm, not form = IncidentForm and keep model = Incident.

I don't see using ModelForm as something that will increase your project's complexity, this is exactly their use case. Doing it another way would be making things complex.

It can be as simple as:

class IncidentForm(ModelForm):
    class Meta:
        model = Incident
        # Define fields you want here, it is best practice not to use '__all__'
        fields = [...]

    def clean(self):
        cleaned_data = super(IncidentForm, self).clean()

        field_1 = cleaned_data.get('field_1')
        field_2 = cleaned_data.get('field_2')
        field_3 = cleaned_data.get('field_3')

        # Values may be None if the fields did not pass previous validations.
        if field_1 is not None and field_2 is not None and field_3 is not None:
            # If fields have values, perform validation:
            if not field_3 == field_1 + field_2:
                # Use None as the first parameter to make it a non-field error.
                # If you feel is related to a field, use this field's name.
                self.add_error(None, ValidationError('field_3 must be equal to the sum of field_1 and filed_2'))

        # Required only if Django version < 1.7 :
        return cleaned_data


class IncidentEdit(UpdateView):
    model = Incident
    form_class = IncidentForm
    fields = visible_field_list
    success_url = '/status'
like image 37
aumo Avatar answered Oct 23 '22 08:10

aumo