wnc_21
wnc_21

Reputation: 1771

DRY up similar form classes

I have an python/django application with simple captcha. Simple captcha is appeared according to some algorithm.

There are two almost same constructors. The difference is just in inheritance. How to avoid code duplication?

class PostCaptchaForm(PostForm):
    captcha = CaptchaField()

    def __init__(self, *args, **kwargs):
        self.request = kwargs['request']
        del kwargs['request']

        super(PostCaptchaForm, self).__init__(*args, **kwargs)

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

        success = self.is_valid()
        utils.update_captcha_access(self.request, success)

        if success:
            return cleaned_data
        else:
            raise forms.ValidationError("captcha validation failed")


class ThreadCaptchaForm(ThreadForm):
    captcha = CaptchaField()  

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request')

        super(ThreadCaptchaForm, self).__init__(*args, **kwargs)

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

        success = self.is_valid()
        utils.update_captcha_access(self.request, success)

        if success:
            return cleaned_data
        else:
            raise forms.ValidationError("captcha validation failed")

Upvotes: 2

Views: 97

Answers (1)

Steve Jalim
Steve Jalim

Reputation: 12195

I'd do it with multiple inheritance, with a base captcha form as a mixin, to be used alongside ThreadForm or PostForm

class CaptchaFormBase(forms.Form):  # or forms.ModelForm, if appropriate

    captcha = CaptchaField()

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request')  
        # this is the same as assigning to self request then deleting the key

        super(CaptchaFormBase, self).__init__(*args, **kwargs)


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

        success = self.is_valid()
        utils.update_captcha_access(self.request, success)

        if not success:
            # this will put things in non_field_errors, you may want to put it in self.errors['captcha']
            raise forms.ValidationError("Captcha validation failed")

        # always make it easy to see that you're returning cleaned_data
        return self.cleaned_data


class PostCaptchaForm(PostForm, CaptchaFormBase):
    pass


class ThreadCaptchaForm(ThreadForm, CaptchaFormBase):
    pass

Upvotes: 3

Related Questions