Search code examples
djangodjango-allauthdjango-registration

Django all_auth and custom form


I'm using django allauth for social login/signup. Also, I've my own signup form as an alternate login/signup. Following are the fields that I'm fetching from the user in the alternate form.

class Profile(models.Model):
    col1 = models.CharField(max_length=50, blank=True, null=True)
    col2 = models.CharField(max_length=50, blank=True, null=True)
    user = models.OneToOneField(User)

So, when the user signs up, it asks for additional fields as well(col1, col2), apart from username, email and password.

Following is the signup view.

user = User.objects.create_user(username, user_email, user_pass)
Profile.objects.create(user=user, col1=col1, col2=col2)
return

So, whenever the user signs up via the alternate form, the above view is called up.

Now, in contrast, when the user signs up from social account FB, it does not ask for extra info, ie col1/col2. It directly signs up without asking for extra info, neither I want it to ask.

I then create a row in Profile model post signup using signals.

@receiver(user_signed_up)
def create_profile(request, user, sociallogin=None, **kwargs):
    if sociallogin:
        if sociallogin.account.provider == 'facebook':
            data = sociallogin.account.extra_data
            col1 = data.get('col1')
            col2 = data.get('col2')
            Profile.objects.create(user=user, col1=col1, col2=col2)

So, (1) my problem is when creating a user using alternate form, no record is inserted in allauth tables, which i find weird.

(2) Consider, I signed up using alternate form using E1 as email id. Now I signup via allauth(FB) with the same id, it throws an error.

(3) How do I send confirmation mail to the users who signed up in alternate form using all_auth.


Solution

  • I played around with the library a bit and finally found the solution to my question. I'm pasting it over here for other's to review.

    Add a signal pre_social_login that'll check for conditions.

    class MySocialAccountAdapter(DefaultSocialAccountAdapter):
    
        def pre_social_login(self, request, sociallogin=None, **kwargs):
            if sociallogin:
                user = User.objects.filter(email=email).first()
                # If user already exists in custom local form, then login directly.
                # Save/Update his details in social login tables.
                if user:
                    # create or update social login tables to maintain the uniformity in the code.
                    token = sociallogin.token.token
                    socialaccount = SocialAccount.objects.filter(user=user).first()
                    if socialaccount:  # If it exists, then update social tables.
                        # updating account.
                        socialaccount.extra_data = extra_data
                        socialaccount.save()
                        # updating token.
                        SocialToken.objects.filter(account=socialaccount) \
                                           .update(token=token)
                    else:  # else create.
                        # saving Social EmailAddress.
                        EmailAddress.objects.create(email=email, user=user)
    
                        # saving social account.
                        provider = 'facebook'
                        kwargs = {
                            'uid': extra_data.get('id'),
                            'provider': provider,
                            'extra_data': extra_data,
                            'user': user
                        }
                        socialaccount = SocialAccount.objects.create(**kwargs)
    
                        # saving social token.
                        app = SocialApp.objects.get(provider=provider)
                        kwargs = {
                            'token': token,
                            'account': socialaccount,
                            'app': app
                        }
                        SocialToken.objects.create(**kwargs)
    
                    # finally login.
                    user.backend = 'django.contrib.auth.backends.ModelBackend'
                    login(request, user)
                    raise ImmediateHttpResponse(redirect(reverse('index')))