Creating a user profile in Python Social Auth in Django

Last week a new project was started, It's the first project where I use python-social-auth, a great library to connect any kind of web application to the social networks in Python.

I really like the architecture of the package, It's very easy to exchange a part of the flow for a custom part made for you. The documentation is good to do basic stuff, but It's necessary to read the code if you want to build your advanced feature in a right way. If you like to read others code like me you are fine. :-)

In this project I wanted to do some basic stuff, just getting some information from the Facebook user and use that to fill a profile.

The pipeline is the one in charge of the process in python-social-auth, so If you want to get data from one of the steps of the process this will be the logical place to customize it.


    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'
        # 'profiles.pipeline.user_details'
    )

So in my case I decided to customize social.pipeline.user.user_details Reading user_details code and Facebook backend code, we come to the conclusion we need to get data from the response variable(not necessary to read facebook backend code to come to that, but you will get it better if you do).

So our user_details might look like this. In my case I put the code in profiles.pipeline.user_details.


    import datetime
    from .models import UserProfile

    # User details pipeline
    def user_details(strategy, details, response, user=None, *args, **kwargs):
        """Update user details using data from provider."""
        if user:
            # ...
            # Just created the user?
            if kwargs['is_new']:
                attrs = {'user': user}
                # I am using also Twitter backend, so I am checking if It's FB
                # or Twitter. Might be a better way of doing this
                if strategy.backend.__class__.__name__ == 'FacebookOAuth2':
                    # We should check values before this, but for the example
                    # is fine
                    fb_data = {
                        'city': response['location']['name'],
                        'gender': response['gender'],
                        'locale': response['locale'],
                        'dob': datetime.fromtimestamp(mktime(strptime(response['birthday'], '%m/%d/%Y')))
                    }
                    attrs = dict(attrs.items() + fb_data.items())
                UserProfile.objects.create(
                    **attrs
                )
            # ...

That's it! You will be able to create a backend with FB data, we could have done this in other places, but this seemed fine for me.

For the record, my UserProfile model would be like this.


    from django.db import models
    from django.contrib.auth.models import User
    class UserProfile(models.Model):
        GENDERS = (
            ('male', 'Male'),
            ('female', 'Female')
        )
        user = models.OneToOneField(User, unique=True)
        gender = models.CharField(max_length=20, null=True, blank=True,
                                  choices=GENDERS)
        city = models.CharField(max_length=250, null=True, blank=True)
        dob = models.DateField(blank=True, null=True)
        locale = models.CharField(max_length=10, blank=True, null=True)
        def __unicode__(self):
            return u'%s profile' % self.user.username

Javier Aguirre

Read more posts by this author.

comments powered by Disqus