Cartucho
Cartucho

Reputation: 3329

Collecting extra user data in Django Social Auth pipeline

I'm using Django Social Auth (v0.7.22) for registering users via Facebook, and that is working OK.

My doubt is how to collect extra data for new users:

  1. How to detect a new user?
  2. Where to store the collected data (in the Django session or pass it through pipeline **kwargs)?

My pipeline looks like:

SOCIAL_AUTH_PIPELINE = (
    'social_auth.backends.pipeline.social.social_auth_user',
    'social_auth.backends.pipeline.misc.save_status_to_session',
    ## My customs ...
    'myapp.pipeline.load_data_new_user',
    'myapp.pipeline.handle_new_user',
    'myapp.pipeline.username',
    ##
    'social_auth.backends.pipeline.user.create_user',
    'social_auth.backends.pipeline.social.associate_user',
    'social_auth.backends.pipeline.social.load_extra_data',
    'social_auth.backends.pipeline.user.update_user_details',
)    

The first custom function just collect the Facebook profile picture:

def load_data_new_user(backend, response, user, *args, **kwargs):
    if user is None:
        if backend.name == "facebook":
            try:
                url = "http://graph.facebook.com/%s/picture?width=200&height=200&redirect=false" % response['id']
                data = json.loads(urllib2.urlopen(url).read())['data']
                return {'avatar': data}
            except StandardError:
                return {'avatar': None}
        else:
            raise ValueError()

My doubts:

  1. I'm checking if user is None for detecting new users (not sure if it's OK to assume that).
  2. I'm storing the avatar metadata in the pipeline's **kwargs instead of use sessions, is it OK? When should I use session.

The other custom functions are based on the Matias Aguirre example, and use sessions for storing the username of new users.

def handle_new_user(request, user, *args, **kwargs):
    if user is None and not request.session.get('saved_username'):
        return HttpResponseRedirect('/form/')


def username(request, user, *args, **kwargs):
    if user is not None:
        username = user.username
    else:
        username = request.session.get('saved_username')
    return {'username': username} 

So, I'm not sure when to use sessions or the "correct idiom" for resolve my problem. Thanks in advance.

Upvotes: 6

Views: 7326

Answers (2)

Cartucho
Cartucho

Reputation: 3329

Matias Aguirre (django socialauth creator) gently answered my question in the DSA google mail list

His answer:

Collecting the data is easy as you saw, but where to put it depends on your project, what you plan to do with the data, and where you expect it to be available. For example, if you plan to put the avatar image on a user profile model, then you should get the profile for the current user and store it there, if you use a custom user with an avatar_url field, then you should fill that field after the user was created, if you plan to download the image and store it local to the server using the username (id, etc) as the filename, then just do it that way too.

The session is usually used as a mechanism of communication with a view.

Regarding the "user is new", there's a flag "is_new" set to True/False when the user is new or not, but it's not updated until the "create_user" is called.

The pipeline entry "save_status_to_session" should be placed before the method that breaks the pipeline flow, in your case handle_new_user.

Thanks everyone.

Upvotes: 6

NT3RP
NT3RP

Reputation: 15370

I was having a similar problem trying to get extra data with Tumblr and Instagram until I found this article.

There seems to be two ways to popular extra_data when a user is created / associated:

*_EXTRA_DATA

This is the easiest way for many pieces of data, but may not be accessible depending on the circumstances. There is a brief mention of it on the OAuth page in the docs.

For example, in your settings file:

FACEBOOK_EXTRA_DATA = [('<actual field from FB>', '<your alias>')]

However, it doesn't appear that the various backends return consistent values, so I had to debug social_auth.backends.pipeline.social.load_extra_data in order to find what fields were accessible. Sometimes, the individual backend describes which fields are available (e.g. see Facebook Backend), or the API documentation, but the most reliable way is to step through their code.

Adding to the pipeline

As you've started, you can define a custom function and hook it into the pipeline. From the linked article (and slightly modified):

def get_user_avatar(backend, details, response, social_user, uid,\
                user, *args, **kwargs):
    url = None
    if getattr(backend, 'name', None) == 'facebook':
        url = "http://graph.facebook.com/%s/picture?type=large" % response['id']

    if url:
        # Save the image somewhere, or just use the URL
        avatar = url
        social_user.extra_data['avatar'] = avatar
        social_user.save()

In either case, once you've done that, the extra data is available via social_user.extra_data['your_field']. Hope that helps.

What about detecting if a user is new or not?

From my understanding, unless you are using django-socialauth for account login, the pipeline is only run on the initial association, so the user will always be new at that point. Beyond that, I'm not 100% sure.

Upvotes: 0

Related Questions