Django-allauth: Disable email changing on social signup form

Created on 29 Apr 2016  路  7Comments  路  Source: pennersr/django-allauth

The question is - how do I achieve that? I have currently this in forms.py:

class SignupForm(UserCreationForm):
    birthdate = forms.DateField(widget=extras.SelectDateWidget(years=BIRTHDATE_YEARS))
    captcha = ReCaptchaField(attrs={'lang': get_language()})

    class Meta:
        model = get_user_model()
        fields = ('username', 'email', 'password1', 'password2', 'first_name', 'last_name', 'gender', 'birthdate', 'city', 'country', 'captcha')

    def signup(self, request, user):
        pass

But when I try to add something like this (and of course configure settings.py afterwards):

from allauth.socialaccount.forms import SignupForm as DefaultSocialSignupForm

class SocialSignupForm(SignupForm, DefaultSocialSignupForm):
    class Meta:
        model = get_user_model()
        fields = ('username', 'email', 'password1', 'password2', 'first_name', 'last_name', 'gender', 'birthdate', 'city', 'country', 'captcha')

    def __init__(self, sociallogin=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['email'].widget.attrs['disabled'] = True

    def clean_email(self):
        super().clean_email(self)
        instance = getattr(self, 'instance', None)
        if instance and instance.pk:
            return instance.email
        else:
            return self.cleaned_data['email']

I get following error when running test server: ImproperlyConfigured: Error importing form class main.forms: "cannot import name 'BaseSignupForm'", which points to allauth.account.forms._base_signup_form_class() function.
So, how to properly achieve this? Thanks in advance!

Most helpful comment

@biswaz I've solved it like this:

class SocialSignupForm(DefaultSocialSignupForm, BaseSignupForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        sociallogin = kwargs.pop('sociallogin')
        if 'email' in sociallogin.account.extra_data:
            self.fields['email'].widget.attrs['readonly'] = True

All 7 comments

I am not sure what you are trying to accomplish, but I see that you are using a ModelForm as a signup form. Don't do that, as allauth needs to be in charge of constructing a User instance and saving it. Make it a plain form, simply deriving from django.forms.Form.

The custom signup form has no access to the built-in form fields such as email. It is only there to provide additional fields, as interfering with the built in ones may cause problems.

So, use the custom signup form only if you want to add a few additional fields to the signup form. If you do need to tweak the behavior of the builtin forms, which it seems you are after, use the ACCOUNT_FORMS setting. Here, you can override all you want ...

I've added in settings.py this: SOCIALACCOUNT_FORMS = {'signup': 'main.forms.SocialSignupForm'}
So it should work, right? But it doesn't. My question remains - how to modify the behavior of that social account signup form in order to disable changing of email field?

@pennersr I think what @MikiSoft meant was that, when a user signs in using a social account he will be presented with the signupform. In this form he can change the email id which has been prefilled from the social account. In many ocassions, including in my use case I dont want the user to change the email id given by the social account. I would prefer to make the EmailField readonly or disabled by using the following code in the SignupForm:

    email = forms.EmailField(
        help_text='Enter you email',
         widget=forms.EmailInput(attrs={'readonly':'readonly'})
    )

or

    email = forms.EmailField(
        help_text='Enter you email',
         widget=forms.EmailInput(attrs={'disabled':'true'})
    )

But both doesnt work. Any ideas?

@biswaz I've solved it like this:

class SocialSignupForm(DefaultSocialSignupForm, BaseSignupForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        sociallogin = kwargs.pop('sociallogin')
        if 'email' in sociallogin.account.extra_data:
            self.fields['email'].widget.attrs['readonly'] = True

@MikiSoft does that disable modification on the server side as well or does it only set the field as disabled? If I'm a script I can still change the email address to something not verified by the auth provider and submit that, right?

@jbothma It only sets field as disabled.

@MikiSoft was this issue resolved? I also need not to make email field visible, editable. I need to implement best practice.

Was this page helpful?
0 / 5 - 0 ratings