Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validating two fields at the same time

I am looking at this piece of documentation:

cleaning and validating fields that depend on each other

The documentation explains how field dependency can be done, but I have a slightly different problem:

Say I have a model with two fields:

class MyModel(models.Model):
    field1 = models.CharField(max_length=200)
    field2 = models.CharField(max_length=200)

And say that one of the two fields is hidden, so the modelform looks like so:

class MyModelForm(forms.ModelForm):
    class Meta:
        ...

        widgets = {'field2': forms.HiddenImput()}

Now, when the user fills out the form, I then (on clean_field1) also fill field2. Now, I want to report any error that happens to field2 as an error about field1. This is because at the moment, the user does not know what he did wrong!

What I tried to do was, in the ModelForm definition:

def clean(self):
    cleaned_data = super(MyModelForm, self).clean()
    # Do something here
    return cleaned_data

As this is what is presented on the Django page. However, the problem is that when the clean method is executed, the dictionary self.errors is empty, so I don't know what to do...

like image 838
5xum Avatar asked Sep 28 '22 04:09

5xum


1 Answers

I am not sure about my answer. However, let's assume that you are using the field1 data in order to generate field2 value. You can generate it using a custom method and assign it to the field in the __init__ method. Which will give you a good way to cleaning the two fields later.

class MyModelForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyModelForm, self).__init__(*args, **kwargs)

        # now lets generate field2 data using field1 data.. 
        self.data['field2'] = self.field[1] * 154220

    class Meta:
        widgets = {'field2': forms.HiddenInput()}    


    def clean_field1(self):
        ## Here you can do validation for field1 only.
        ## Do it like field2 is not exisited. 


    def clean_field2(self):
        ## Here you can do validation for field2 only.
        ## Do it like field1 is not exisited. 

    def clean(self):
        """
        In here you can validate the two fields
        raise ValidationError if you see anything goes wrong. 
        for example if you want to make sure that field1 != field2
        """
        field1 = self.cleaned_data['field1']
        field2 = self.cleaned_data['field2']

        if field1 == field2:
            raise ValidationError("The error message that will not tell the user that field2 is wrong.")

        return self.cleaned_data

Update

In case you want the clean method to raise the error in a specific field:

Note that any errors raised by your Form.clean() override will not be associated with any field in particular. They go into a special “field” (called all), which you can access via the non_field_errors() method if you need to. If you want to attach errors to a specific field in the form, you need to call add_error().

So from Django documentation you can use add_error() to do what you want to achieve.

The code can be in this way

def clean(self):
    """
    In here you can validate the two fields
    raise ValidationError if you see anything goes wrong. 
    for example if you want to make sure that field1 != field2
    """
    field1 = self.cleaned_data['field1']
    field2 = self.cleaned_data['field2']

    if field1 == field2:
        # This will raise the error in field1 errors. not across all the form
        self.add_error("field1", "Your Error Message")

    return self.cleaned_data

Note that the above method is new with Django 1.7 and above.

https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.add_error

like image 162
Othman Avatar answered Oct 03 '22 05:10

Othman