Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to populate user profile with django-allauth provider information?

I'm using django-allauth for my authentication system. I need that when the user sign in, the profile module get populated with the provider info (in my case facebook).

I'm trying to use the pre_social_login signal, but I just don't know how to retrieve the data from the provider auth

from django.dispatch import receiver
from allauth.socialaccount.signals import pre_social_login

@receiver(pre_social_login)

def populate_profile(sender, **kwargs):
    u = UserProfile( >>FACEBOOK_DATA<< )
    u.save()

Thanks!!!

like image 515
Tomer Simis Avatar asked Jan 25 '13 13:01

Tomer Simis


4 Answers

The pre_social_login signal is sent after a user successfully authenticates via a social provider, but before the login is actually processed. This signal is emitted for social logins, signups and when connecting additional social accounts to an account.

So it is sent before the signup is fully completed -- therefore this not the proper signal to use.

Instead, I recommend you use allauth.account.signals.user_signed_up, which is emitted for all users, local and social ones.

From within that handler you can inspect whatever SocialAccount is attached to the user. For example, if you want to inspect Google+ specific data, do this:

user.socialaccount_set.filter(provider='google')[0].extra_data

UPDATE: the latest development version makes this a little bit more convenient by passing along a sociallogin parameter that directly contains all related info (social account, token, ...)

like image 152
pennersr Avatar answered Nov 16 '22 03:11

pennersr


Here is a Concrete example of @pennersr solution :

Assumming your profile model has these 3 fields: first_name, email, picture_url

views.py:

@receiver(user_signed_up)
def populate_profile(sociallogin, user, **kwargs):    

    if sociallogin.account.provider == 'facebook':
        user_data = user.socialaccount_set.filter(provider='facebook')[0].extra_data
        picture_url = "http://graph.facebook.com/" + sociallogin.account.uid + "/picture?type=large"            
        email = user_data['email']
        first_name = user_data['first_name']

    if sociallogin.account.provider == 'linkedin':
        user_data = user.socialaccount_set.filter(provider='linkedin')[0].extra_data        
        picture_url = user_data['picture-urls']['picture-url']
        email = user_data['email-address']
        first_name = user_data['first-name']

    if sociallogin.account.provider == 'twitter':
        user_data = user.socialaccount_set.filter(provider='twitter')[0].extra_data
        picture_url = user_data['profile_image_url']
        picture_url = picture_url.rsplit("_", 1)[0] + "." + picture_url.rsplit(".", 1)[1]
        email = user_data['email']
        first_name = user_data['name'].split()[0]

    user.profile.avatar_url = picture_url
    user.profile.email_address = email
    user.profile.first_name = first_name
    user.profile.save()         

If you are confused about those picture_url variable in each provider. Then take a look at the docs:

facebook:

picture_url = "http://graph.facebook.com/" + sociallogin.account.uid + "/picture?type=large" Docs

linkedin:

picture_url = user_data['picture-urls']['picture-url'] Docs

twitter:

picture_url = picture_url.rsplit("_", 1)[0] + "." + picture_url.rsplit(".", 1)[1] Docs And for the rsplit() take a look here

Hope that helps. :)

like image 35
Ahtisham Avatar answered Nov 16 '22 02:11

Ahtisham


I am doing in this way and taking picture (field) url and google provider(field) as an example.

socialaccount_obj = SocialAccount.objects.filter(provider='google', user_id=self.user.id)
   picture = "not available"
   if len(socialaccount_obj):
            picture = socialaccount_obj[0].extra_data['picture']

make sure to import : from allauth.socialaccount.models import SocialAccount

like image 22
Wahib Ul Haq Avatar answered Nov 16 '22 04:11

Wahib Ul Haq


There is an easier way to do this.

Just add the following to your settings.py. For example, Linked in...

SOCIALACCOUNT_PROVIDERS = {
'linkedin': {
    'SCOPE': [
        'r_basicprofile',
        'r_emailaddress'
    ],
    'PROFILE_FIELDS': [
        'id',
        'first-name',
        'last-name',
        'email-address',
        'picture-url',
        'public-profile-url',
    ]
}

The fields are automatically pulled across.

like image 43
Ryan Avatar answered Nov 16 '22 04:11

Ryan