Jay Jung
Jay Jung

Reputation: 1885

How to require only one of two fields at the form level

Users only have to fill out one of two fields.
How would I require this? And where would it be?

I'm trying to put it in the save, but I believe it belongs elsewhere since the validationerror pops up as a Django error screen, and not a field validation error. Here's what I've tried:

class SignupForm(forms.Form):
    learn1 = forms.CharField(max_length=50, label='Learn', required=False)
    teach1 = forms.CharField(max_length=50, label='Teach', required=False)

    class Meta:
        model = Profile

    def save(self, user):
        if not self.cleaned_data['learn1'] or self.cleaned_data['teach1']:
            raise forms.ValidationError("Specify at least one")
        user.is_profile_to.learn1 = self.cleaned_data['learn1']
        user.is_profile_to.teach1 = self.cleaned_data['teach1']
        user.save()
        user.is_profile_to.save()  

Upvotes: 1

Views: 150

Answers (2)

nigel222
nigel222

Reputation: 8222

For completeness, you can also handle this at the view level (especially, class-based). You use form.add_error() and return form_invalid():

class MyView( FormView): # or UpdateView, etc.

    # usual definitions

    def form_valid( self, form):
        if not form.cleaned_data['learn1'] and not form.cleaned_data['teach1']:
            form.add_error('', 'You must specify either "Learn" or "Teach"')
            return self.form_invalid( form)

        super().form_valid( form)  # if you want the standard stuff, or

        # process the form
        # return a response

The first argument of form.add_error is the name of the form field to attach the error to. '' specifies a non-form error. You might want the same error attached to both fields instead, in which case just attach two errors

        form.add_error('learn1', 'You must specify either "Learn" or "Teach"')
        form.add_error('teach1', 'You must specify either "Learn" or "Teach"')
        return self.form_invalid( form)

Doing it this way allows you to access the view context in deciding whether or not something is an error. You can consult the url args or kwargs, or consider who is the user.

Upvotes: 0

Exprator
Exprator

Reputation: 27533

def clean(self):
        cleaned_data = super().clean()
        if not self.cleaned_data['learn1'] and not self.cleaned_data['teach1']:
            raise forms.ValidationError("Specify at least one")
        else:
            return cleaned_data


def save(self, user):
        user.is_profile_to.learn1 = self.cleaned_data['learn1']
        user.is_profile_to.teach1 = self.cleaned_data['teach1']
        user.save()
        user.is_profile_to.save()  

Upvotes: 3

Related Questions