Customizing Django allauth's socialaccount sig

2019-06-26 18:52发布

I'm trying to modify the signup form which the user is shown when logging in from a socialaccount provider.

Here's me custom signup form code:

from allauth.socialaccount.forms import SignupForm
from allauth.account.forms import SetPasswordField, PasswordField


class SocialPasswordedSignupForm(SignupForm):

    password1 = SetPasswordField(label=_("Password"))
    password2 = PasswordField(label=_("Password (again)"))

    def confirm_password(self):
        print('entered confirm_password')
        if ("password1" in self.cleaned_data
                and "password2" in self.cleaned_data):
            print('password fields found')
            if self.cleaned_data['password1'] != self.cleaned_data['password2']:
                print('passwords not equal')
                raise forms.ValidationError(_("You must type the same password"
                                              " each time."))
            print('passwords equal')
            return self.cleaned_data["password1"]
        else:
            print('passwords not found in form')
            raise forms.ValidationError(_("Password not found in form"))

    def signup(self, request, user):
        print('signup in SocialPasswordedSignupForm')
        password = self.confirm_password()
        user.set_password(password)
        user.save()

settings.py:

SOCIALACCOUNT_FORMS = {
    'signup': 'users.forms.SocialPasswordedSignupForm'
}

But the problem is, that my signup method never gets called, and so, the confirm_password method isn't called either, and there's no validation on password being done. That is, if I enter two different passwords, the first password is saved.

What could be wrong?

2条回答
劳资没心,怎么记你
2楼-- · 2019-06-26 19:40

Are you setting this value SOCIALACCOUNT_AUTO_SIGNUP = False ? This is to make sure that upon successful authentication the user is redirected to your signup form.

I came to your link because I had to implement exact same feature. So this is how I have done it on my end.

forms.py

class SocialPasswordedSignupForm(SignupForm):

    password1 = SetPasswordField(max_length=6,label=("Password"))
    password2 = PasswordField(max_length=6, label=("Password (again)"))

    #taken from https://github.com/pennersr/django-allauth/blob/master/allauth/account/forms.py

    def clean_password2(self):
        if ("password1" in self.cleaned_data and "password2" in self.cleaned_data):
            if (self.cleaned_data["password1"] != self.cleaned_data["password2"]):
                raise forms.ValidationError(("You must type the same password each time."))
        return self.cleaned_data["password2"]

    def signup(self, request, user):
        user.set_password(self.user, self.cleaned_data["password1"])
        user.save()

I got the idea to explore the original code in https://github.com/pennersr/django-allauth/blob/master/allauth/account/forms.py and found out that there is no such function like clean_password1() but there is clean_password2() which is doing the intended work. So just copied it as it is and everything worked :)

If it works for you then don't forget to accept it as answer.

查看更多
祖国的老花朵
3楼-- · 2019-06-26 19:50

I basically created my version of the SignupForm class:

from allauth.account.forms import SetPasswordField, PasswordField
from allauth.account import app_settings
from allauth.account.utils import user_field, user_email, user_username
from django.utils.translation import ugettext_lazy as _


class SocialPasswordedSignupForm(BaseSignupForm):

    password1 = SetPasswordField(label=_("Password"))
    password2 = SetPasswordField(label=_("Confirm Password"))

    def __init__(self, *args, **kwargs):
        self.sociallogin = kwargs.pop('sociallogin')
        user = self.sociallogin.user
        # TODO: Should become more generic, not listing
        # a few fixed properties.
        initial = {'email': user_email(user) or '',
                   'username': user_username(user) or '',
                   'first_name': user_field(user, 'first_name') or '',
                   'last_name': user_field(user, 'last_name') or ''}
        kwargs.update({
            'initial': initial,
            'email_required': kwargs.get('email_required',
                                         app_settings.EMAIL_REQUIRED)})
        super(SocialPasswordedSignupForm, self).__init__(*args, **kwargs)

    def save(self, request):
        adapter = get_adapter()
        user = adapter.save_user(request, self.sociallogin, form=self)
        self.custom_signup(request, user)
        return user

    def clean(self):
        super(SocialPasswordedSignupForm, self).clean()
        if "password1" in self.cleaned_data \
                and "password2" in self.cleaned_data:
            if self.cleaned_data["password1"] \
                    != self.cleaned_data["password2"]:
                raise forms.ValidationError(_("You must type the same password"
                                              " each time."))

    def raise_duplicate_email_error(self):
        raise forms.ValidationError(
            _("An account already exists with this e-mail address."
              " Please sign in to that account first, then connect"
              " your %s account.")
            % self.sociallogin.account.get_provider().name)

    def custom_signup(self, request, user):
        password = self.cleaned_data['password1']
        user.set_password(password)
        user.save()

Worked for me, flawlessly. You guys can compare the default SignupForm in socialaccount.forms and my implementation, for the differences.

查看更多
登录 后发表回答