1

OK, so I have UserUpdateForm and RegistrationForm. Each with this function currently:

def clean_email(self):
    email = self.cleaned_data.get('email')

    if email and User.objects.filter(email=email).exclude(pk=self.instance.id).count():
        raise forms.ValidationError('Email already in use.')
    return email

I was wondering what would be the ideal way to avoid this duplication.

Please advise.

** UPDATE **

What if I needed to call the parent function but all some stuff to it, say I have this:

def clean_email(self):
    email = self.cleaned_data.get('email')

    if email and User.objects.filter(email=email).exclude(pk=self.instance.id).count():
        raise forms.ValidationError('Email already in use.')

    ### THIS BIT IS ONLY NEEDED IN ONE OF THE CHILD FORMS ###
    # Check whether the email was change or not
    if self.instance.email != email:

        # To not change the email in our database until the new one is verified
        return self.instance.email
    ###

    return email

4 Answers 4

1

Expanding on msc's answer, create a base form and have UserUpdateForm and RegistrationForm extend your base form.

class YourBaseForm(ModelForm):

    def clean_email(self):
        email = self.cleaned_data.get('email')

        if email and User.objects.filter(email=email).exclude(pk=self.instance.id).count():
            raise forms.ValidationError('Email already in use.')
        return email

class UserUpdateForm(YourBaseForm):

    # ....add unique fields or methods here

class RegistrationForm(YourBaseForm):

    # ....add unique fields or methods here

The clean_email method will now be available on both UserUpdateForm and RegistrationForm objects.

For a bit more information about form inheritance have a glance at the docs.

UPDATE:

If you need to change the method in the subclass then you can override it but include a call to the super's clean_email method like so -

UserUpdateForm(YourBaseForm):

    def clean_email(self):
        email = super(UserUpdateForm, self).clean_email()
        if self.instance.email != email:
            return self.instance.email
        return email
Sign up to request clarification or add additional context in comments.

1 Comment

@adamsilver I've updated my answer with new code - you might want to google 'python super' to get more info (I included a link but the python docs often take me longer to figure out than a good explanation on SO)
1

Use signal for example:

 models.py

 @receiver(pre_save, sender=User)
 def User_pre_save(sender, **kwargs):
     email = kwargs['instance'].email
     username = kwargs['instance'].username

     if not email: raise ValidationError("email required")
     if sender.objects.filter(email=email).exclude(username=username).count(): raise ValidationError("email is already exist")      

views.py

 def view_name(request):
     try:
          .......
     except ValidationError, e:
        message_dict = e.update_error_dict({})
        state = message_dict[NON_FIELD_ERRORS] 
 return render(request, 'page.html', {'state':state}) 

1 Comment

Although the data will not be stored, this will set invalid data on the object. The form should do the full validation and produce all the necessary errors.
1

You can create a base form that has that function, then have both forms extend that one.

2 Comments

Any explanation for downvote? Sounds correct. Could use more detail (may be more comment-ish).
SO should reduce more reputations of the ones who down vote without any comment
1

Inherit from a base form (like other answer suggests) or since the form is derived from your model, you can put it directly in model cleaning. The only problem with this approach is that it hits the database every time. Just showing you the options.

... your model's clean() method will be called before any uniqueness checks are made. See Validating objects for more information on the model's clean() hook.

class MyModel(models.Model):
   # ... your model
   def clean(self):
        if self.email and User.objects.filter(email=self.email).exclude(pk=self.id).count():
        raise ValidationError('Email already in use.')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.