pythondjangofacebook-graph-apidjango-rest-frameworkdjango-oauth

Saving Facebook picture in Django Model (REST Social Oath2)


This question is about saving Facebook Profile pictures in the Django model automatically, using https://github.com/PhilipGarnero/django-rest-framework-social-oauth2 library.

Edit: There are 2 ways to solve this question: Save the URL of the image in CharField() or Save the image itself using ImageField(). Both solutions will do.


The above library allows me to create and authenticate users using bearer tokens. I have the created the profile model:

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='userprofile')
    photo = models.FileField(blank=True) # OR
    ######################################
    url = 'facebook.com{user id}/picture/'
    photo = models.CharField(default=url)

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.userprofile.save()

Which automatically creates user profiles for each user. Now, I would like to add the following code to save the photo from Facebook. Facebook API requires user id to get this picture.

photo = 'https://facebook/{user-id}/picture/'
UserProfile.objects.create(user=instance, photo=photo)

The above is not working because

1) I can't figure out where to get the user id from.

2) The image can't be stored like that, I need to convert it to bytes or some other method.


Solution

  • There is a VERY simple solution for that. Use the python-social-auth pipelines.

    The way this thing work is just like middleware, you can add in your settings page to the SOCIAL_AUTH_PIPELINE section a function that will run every time the user is authenticated using the social_django.

    An example:

    In your settings page, add the following:

    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',
        'home.pipeline.save_profile',
    )
    

    Look at home.pipeline.save_profile, this is a new pipeline in home.pipeline file. (Change it into your own user module folder)

    In there (home.pipeline) add the following:

    from .models import UserProfile
    
    def save_profile(backend, user, response, *args, **kwargs):
        if backend.name == "facebook":
            UserProfile.objects.create(
                user=user, 
                photo_url=response['user']['picture']
            )
    

    This is an example. You need to change it for get/update in case the user already logged in. Also, try and play with the response argument, there might be different data you can use there.

    One last thing, make sure you add the picture attribute into your settings:

    SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
      'fields': 'id, name, email, picture'
    }
    

    http://python-social-auth.readthedocs.io/en/latest/backends/facebook.html

    https://godjango.com/122-custom-python-social-auth-pipeline/

    https://github.com/python-social-auth/social-app-django