Igor
Igor

Reputation: 479

Django modelform remove "required" attribute based on other field choice

I have ModelForm with several fields. Some of fields are required, some not. Also I have Select field with different choices, and I want to make some of fields "required" or not based on this Select field choice.

I tried in clean() method of Form

def clean(self):
    cleaned_data = self.cleaned_data
    some_field = cleaned_data.get("some_field")
    if some_field == 'some_value':
          self.fields['other_field'].required = False
    return cleaned_data

but it doesn't work

Upvotes: 7

Views: 7423

Answers (4)

LuisFerchx
LuisFerchx

Reputation: 47

I found a possible solution. You can use your condition before form.is_valid() and include your change in your field.

if form.data['tid_id'] is None: # my condition
    form.fields['prs_razonsocial'].required = True
    form.fields['prs_nombres'].required = False
    form.fields['prs_apellidos'].required = False
if form.is_valid():
...

Upvotes: 0

Marboni
Marboni

Reputation: 2459

If you like to print error message for required field in common way, you can do this:

def clean(self):
    cleaned_data = super(PasswordChangeForm, self).clean()
    token = cleaned_data.get('token')
    old_password = cleaned_data.get('old_password')
    if not token and not old_password:
        self._errors['old_password'] = self.error_class([self.fields['old_password'].error_messages['required']])

Upvotes: 2

André Caron
André Caron

Reputation: 45244

See the Django documentation on Cleaning and validating fields that depend on each other. The standard practice would be to perform the following handling instead:

def clean(self):
    cleaned_data = self.cleaned_data
    some_field = cleaned_data.get("some_field")
    if some_field == 'some_value':
          # 'other_field' is conditionally required.
          if not cleaned_data['other_field']:
              raise forms.ValidationError("'Other_field' is required.")
    return cleaned_data

Upvotes: 10

Mark Lavin
Mark Lavin

Reputation: 25164

You have the right idea but the problem is that the individual field validations have already run before the form clean. You have a couple options. You could make the field not required and handle the logic of when it is required in your form.clean. Or you could leave the field as required and remove the validation errors it might raise in the clean.

def clean(self):
    cleaned_data = self.cleaned_data
    some_field = cleaned_data.get("some_field")
    if some_field == 'some_value':
          if 'other_field' in self.errors:
              del self.errors['other_field']
              cleaned_data['other_field'] = None
    return cleaned_data

This has some problems in that it removes all errors, not just missing/required errors. There is also a problem with the cleaned_data. You now have a required field which isn't in the cleaned_data which is why I've added it as None. The rest of your application will have to handle this case. It might seem odd to have a required field which doesn't have a value.

Upvotes: 3

Related Questions