Retrieving profile picture from google and facebook in python-social-auth
Asked Answered
O

4

12

How can I retrieve profile picture and date of birth from google and facebook using python-social-auth by extending pipeline? I've read that I can make functions to do so and set path to them but I don't know the attribute names that I must retrieve. Please help!

Ozenfant answered 11/4, 2015 at 8:19 Comment(0)
V
14

To get avatars from social login, you need create a pipeline.py file in your app and add this lines to settings.py:

SOCIAL_AUTH_PIPELINE = (

    'social.pipeline.social_auth.social_details',
    'social.pipeline.social_auth.social_uid',
    'social.pipeline.social_auth.auth_allowed',
    'social.pipeline.social_auth.social_user',
    'social.pipeline.user.get_username',
    'social.pipeline.user.create_user',
    'social.pipeline.social_auth.associate_user',
    'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details',
    'apps.users.pipeline.get_avatar', # This is the path of your pipeline.py
    #and get_avatar is the function.
)

and later add this content to your pipeline.py file

def get_avatar(backend, strategy, details, response,
        user=None, *args, **kwargs):
    url = None
    if backend.name == 'facebook':
        url = "http://graph.facebook.com/%s/picture?type=large"%response['id']
    if backend.name == 'twitter':
        url = response.get('profile_image_url', '').replace('_normal','')
    if backend.name == 'google-oauth2':
        url = response['image'].get('url')
        ext = url.split('.')[-1]
    if url:
        user.avatar = url
        user.save()
Valdis answered 16/10, 2015 at 1:55 Comment(1)
Be sure to use HTTPS and not HTTP when accessing graph.facebook.comTertia
T
6

Here's what I have used to save pictures for Facebook:

def save_profile_picture(backend, user, response, details,
                         is_new=False,*args,**kwargs):

    if backend.__class__.__name__ == 'FacebookOAuth2':
        up = UserProperties.objects.get_or_create(user=user) #RETURNS TUPLE (instance, created(boolean))
        if not up[0].photo:
            url = 'http://graph.facebook.com/{0}/picture'.format(response['id'])
            response = urllib.request.urlopen(url)
            io = BytesIO(response.read())
            up[0].photo.save('profile_pic_{}.jpg'.format(user.pk), File(io))
            up[0].save() 

Save this function into a file, for instance, pipelines.py, and then add the function to your SOCIAL_AUTH_PIPELINE in your settings.

SOCIAL_AUTH_PIPELINE = (
    'social.pipeline.social_auth.social_details',
    'social.pipeline.social_auth.social_uid',
    'social.pipeline.social_auth.auth_allowed',
    'social.pipeline.social_auth.social_user',
    'social.pipeline.user.get_username',
    'social.pipeline.social_auth.associate_by_email', 
    'social.pipeline.user.create_user',
    'social.pipeline.social_auth.associate_user',
    'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details',
    'projects.pipeline.save_profile_picture', #save facebook profile image,
)

For Facebook you need to create your own Facebook app. You can only retrieve information and pictures from users who have given you the permission to do so. Same rules more or less apply for Google. Read their API docs for more detail.

Tin answered 11/4, 2015 at 9:46 Comment(5)
So what I understood is that I must find a URL on which Google+ serves its images and use that to retrieve profile picture and then override my pipeline. Did I get it right?Ozenfant
Yes. Read their docs for more details. You need to add your functions to the pipeline, in the correct place to have the desired behaviour. And to the one who down voted: I gave a good answer how to get started. You cannot expect people to write the whole program for other people, but give answers that take the OP to the right track, as was the case here. That kind of negativity is unfortunately rampant here.Tin
I have another doubt, I've a custom model which inherits the user model from Django.contrib.author and then two more fields for DOB and profile picture. When I signed in with Google using OAuth2, the django.contrib.auth.user in the admin panel got its values but my custom model wasn't linked on a one to one basis with it. Any advice on how I might be able to do that?Ozenfant
It seems google now needs a api request GET https://www.googleapis.com/plus/v1/people/userId, which will return a json response containing the requested image. See this answerMongoose
Be sure to use HTTPS and not HTTP when accessing graph.facebook.comTertia
R
4

The above answers may not work (it did not work for me) as the facebook profile URL does not work anymore without accesstoken. The following answer worked for me.

def save_profile(backend, user, response, is_new=False, *args, **kwargs):
    if is_new and backend.name == "facebook":
        # The main part is how to get the profile picture URL and then do what you need to do
        Profile.objects.filter(owner=user).update(
            imageUrl='https://graph.facebook.com/{0}/picture/?type=large&access_token={1}'.format(response['id'],
                                                                                                  response[
                                                                                                      'access_token']))
    elif backend.name == 'google-oauth2':
        if is_new and response.get('picture'):
            Profile.objects.filter(owner=user).update(imageUrl=response['picture'])

add to the pipeline in setting.py,

SOCIAL_AUTH_PIPELINE+ = ('<full_path>.save_profile')
Roseline answered 23/12, 2020 at 0:44 Comment(0)
K
1

Just to extend sadat's answer which works perfectly for saving the url. If you are wanting to save the actual image from the url to a django imagefield would need to do the below:

import requests
from io import BytesIO
from django.core import files

def save_profile(backend, user, response, is_new=False, *args, **kwargs):
if is_new and backend.name == "facebook":
    
    picture_url='https://graph.facebook.com/{0}/picture/?type=large&access_token={1}'.format(response['id'],
                                                                                              response[
                                                                                                  'access_token']))   
    file_name = f"{uuid.uuid4()}.jpeg"
            resp = requests.get(picture_url)
            if resp.status_code == requests.codes.ok:
                fp = BytesIO()
                fp.write(resp.content)
  
                profile.image.save(file_name, files.File(fp))
                profile.save()
Killigrew answered 12/5, 2021 at 21:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.