Skip to content

Latest commit

 

History

History
452 lines (281 loc) · 15.5 KB

README.rest

File metadata and controls

452 lines (281 loc) · 15.5 KB

Django Facebook by Thierry Schellenbach (mellowmorning.com)

https://secure.travis-ci.org/tschellenbach/Django-facebook.png?branch=master

Contributions are strongly appreciated. Seriously, give github a try, fork and get started :)

News

Now with support for django custom user models

Demo & About

Django Facebook enables your users to easily register using the Facebook API. It converts the Facebook user data and creates regular User and Profile objects. This makes it easy to integrate with your existing Django application.

I've built it for my startup Fashiolista.com and it's currently used in production with thousands of signups per day. For a demo of the signup flow have a look at Fashiolista's landing page (fashiolista.com)

After registration Django Facebook gives you access to user's graph. Allowing for applications such as:

  • Open graph/ Timeline functionality
  • Seamless personalization
  • Inviting friends
  • Finding friends
  • Posting to a users profile

Updates and tutorials can be found on my blog mellowmorning

Further demos and tutorials will soon be available on django-facebook.com

Features

  • Access the Facebook API, from:
    • Your website (Using javascript OAuth)
    • Facebook canvas pages (For building facebook applications)
    • Mobile (Or any other flow giving you a valid access token)
  • Django User Registration (Convert Facebook user data into a user model)
  • Store likes, friends and user data locally.
  • Facebook FQL access
  • OAuth 2.0 compliant
  • Automated reauthentication (For expired tokens)
  • Includes Open Facebook (stable and tested Python client to the graph API)

Installation

Clone the source code or use pip install django_facebook.

Create a Facebook App

You need a facebook app to use the open graph API and make the login process work. If you don't have a facebook app, now is the time to create one. You can create a facebook app at this url.

Facebook authentication only works if the domain you are working on matches your app domain. Be sure to configure the right app domain in your facebook application settings.

An example:

Your site is www.fashiolista.com, your app domain is set to fashiolista.com and you do your development at local.fashiolista.com. If you try to authenticate with Facebook from a different domain you will get an authentication error.

Settings

Define the following settings in your settings.py file:

FACEBOOK_APP_ID
FACEBOOK_APP_SECRET

Url config, context processor, auth backend

add django facebook to your installed apps:

'django_facebook',

Add this line to your context processors (TEMPLATE_CONTEXT_PROCESSORS setting):

'django_facebook.context_processors.facebook',
# and add request if you didn't do so already
'django.core.context_processors.request',

The full setting on a new django 1.5 app looks like this:

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
    'django.core.context_processors.tz',
    'django.core.context_processors.request',
    'django.contrib.messages.context_processors.messages',
    'django_facebook.context_processors.facebook',
)

Add this to your AUTHENTICATION_BACKENDS setting:

'django_facebook.auth_backends.FacebookBackend',

The full setting on a new django 1.5 app looks like this:

AUTHENTICATION_BACKENDS = (
    'django_facebook.auth_backends.FacebookBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Now, add this line to your url config:

(r'^facebook/', include('django_facebook.urls')),
(r'^accounts/', include('django_facebook.auth_urls')), #Don't add this line if you use django registration or userena for registration and auth.

Update your models

The following step depends on your version of Django. Django versions before 1.5 need to use a custom profile model. Whereas Django 1.5 and up can use a custom user model.

Django 1.5

If you don't already have a custom user model, simply uses the provided model by setting your AUTH_USER_MODEL to FacebookUser:

AUTH_USER_MODEL = 'member.FacebookUser'

Alternatively use the abstract model provided in django_facebook.models.FacebookProfileModel

Django < 1.5

If you don't already have a custom Profile model, simply uses the provided model by setting your AUTH_PROFILE_MODULE to FacebookProfile:

AUTH_PROFILE_MODULE = 'django_facebook.FacebookProfile'

Be sure to run manage.py syncdb after setting this up.

Otherwise Django Facebook provides an abstract model which you can inherit like this:

from django_facebook.models import FacebookProfileModel


class MyCustomProfile(FacebookProfileModel):
    user = models.OneToOneField('auth.User')
    ....

from django.contrib.auth.models import User
from django.db.models.signals import post_save

#Make sure we create a MyCustomProfile when creating a User
def create_facebook_profile(sender, instance, created, **kwargs):
    if created:
        MyCustomProfile.objects.create(user=instance)

post_save.connect(create_facebook_profile, sender=User)

Don't forget to update your database using syncdb or south after this step.

Note: You need a profile model attached to every user model. For new accounts this will get created automatically, but you will need to migrate older accounts.

Congratulations Right now you should have a working registration/connect/login in flow available at /facebook/example/! Test if everything is working and ensure you didn't miss a step somewhere. If you encounter any difficulties please open an issue.

Customize and integrate into your site

Now it's time to customize things a little. For an example you can look at connect.html in the templates directory.

First load the css:

<link href="{{ STATIC_URL }}css/facebook.css" type="text/css" rel="stylesheet" media="all" />

Secondly load the javascript:

{% include 'django_facebook/_facebook_js.html' %}

If you encounter issues here you probably don't have django static files setup correctly. Alternatively you might be missing the context processor.

Subsequently implement a form which calls Facebook via javascript. Note that you can control which page to go to after connect using the next input field.

<form action="{% url facebook_connect %}?facebook_login=1" method="post">
<a href="javascript:void(0);" style="font-size: 20px;" onclick="F.connect(this.parentNode);">Register, login or connect with facebook</a>
<input type="hidden" value="{{ request.path }}" name="next" />
<input type="hidden" value="{{ request.path }}" name="register_next" />
<input type="hidden" value="{{ request.path }}" name="error_next" />

{% csrf_token %} </form>

Redirects

For most applications you can simply use the next, register next and error next parameters to control the post registration flow. The "next" parameter provides the default next page for login, connect, error or register actions. "register_next" and "error_next" allow you to customize the next page for those specific scenarios. This is usefull when you for instance want to show an introduction page to new users.

Flows

  • Login (login_next, next, default)
  • Connect (connect_next, next, default)
  • Register (register_next, next, default)
  • Error (error_next, next, default)

The default redirect is specified by the FACEBOOK_LOGIN_DEFAULT_REDIRECT setting.

If the default customizability isn't adequate for your needs you can also subclass the default registration backend.

class CustomBackend(FacebookRegistrationBackend):
def post_connect(action):

# go as crazy as you want, just be sure to return a response response = HttpRedirect('/something/') if action is CONNECT_ACTIONS.LOGIN:

response = HttpRedirect('/')

return response

Common bugs

Django Facebook expects that you are using static files in order to load the required javascript. If you are not using staticfiles you should load facebook.js provided in the static directory manually.

Another common issue are the url matching settings from Facebook. Facebook requires you to fill in a domain for your application. In order for things to work with local development you need to use the same domain. So if you production site is www.mellowmorning.com you should run your development server on something like local.mellowmorning.com in order for facebook to allow authentication.

If you encounter any difficulties please open an issue.

Registration Backends

Registration Backends

By default Django Facebook ships with its own registration system. It provides a basic manual registration flow and the option to connect with Facebook.

If you are looking for something more complicated it's possible to integrate with Userena or Django Registration. To add support for these systems we use the FACEBOOK_REGISTRATION_BACKEND setting.

Django Registration support Create a registration backend which subclasses both Django Facebook and Django Registration's registration backend. An example is included in facebook_example/registration_backends.py

::

# in registration_backends.py class DjangoRegistrationDefaultBackend(DefaultBackend, NooptRegistrationBackend):

''' The redirect behaviour will still be controlled by the

post_error post_connect

functions the form and other settings will be taken from the default backend ''' pass

# in your settings file FACEBOOK_REGISTRATION_BACKEND = 'registration.backends.default.DefaultBackend'

Django Userena support

Django Userena is easier to work with than Django Registration. It is however hard to setup unittesting with Userena, so the integration between Django Facebook and Userena might not work. Please report any bugs you run into.

FACEBOOK_REGISTRATION_BACKEND = 'django_facebook.registration_backends.UserenaBackend'

Also have a look at the userena settings file in the facebook example project. It provides a clear example of how to configure Userena and Django Facebook to work together.

Other registration systems

Supporting any other registration system is quite easy. Adjust the above settings to point to your own code. Note that the form's save method needs to return the new user object.

Signals

Django-facebook ships with a few signals that you can use to easily accommodate Facebook related activities with your project.

facebook_user_registered signal is sent whenever a new user is registered by Django-facebook, for example:

from django_facebook.utils import get_user_model
from django_facebook import signals

def fb_user_registered_handler(sender, user, facebook_data, \*\*kwargs):
    # Do something involving user here

signals.facebook_user_registered.connect(user_registered, sender=get_user_model())

facebook_pre_update signal is sent just before Django-facebook updates the profile model with Facebook data. If you want to manipulate Facebook or profile information before it gets saved, this is where you should do it. For example:

from django_facebook import signals
from django_facebook.utils import get_user_model

def pre_facebook_update(sender, user, profile, facebook_data, \*\*kwargs):
    profile.facebook_information_updated = datetime.datetime.now()
    # Manipulate facebook_data here

signals.facebook_pre_update.connect(pre_facebook_update, sender=get_user_model())

facebook_post_update signal is sent after Django-facebook finishes updating the profile model with Facebook data. You can perform other Facebook connect or registration related processing here.

from django_facebook import signals
from django_facebook.utils import get_user_model

def post_facebook_update(sender, user, profile, facebook_data, \*\*kwargs):
    # Do other stuff

signals.facebook_post_update.connect(post_facebook_update, sender=get_user_model())

facebook_post_store_friends signal is sent after Django-facebook finishes storing the user's friends.

from django_facebook import signals
from django_facebook.utils import get_user_model

def post_friends(sender, user, friends, current_friends, inserted_friends, \*\*kwargs):
    # Do other stuff

facebook_post_store_friends.connect(post_friends, sender=get_user_model())

facebook_post_store_likes signal is sent after Django-facebook finishes storing the user's likes. This is usefull if you want to customize what topics etc to follow.

from django_facebook import signals
from django_facebook.utils import get_user_model

def post_likes(sender, user, likes, current_likes, inserted_likes, \*\*kwargs):
    # Do other stuff

facebook_post_store_likes.connect(post_likes, sender=get_user_model())

Celery, Performance and Optimization

Facebook APIs can take quite some time to respond. It's very common that you will wait between 1-3 seconds for a single API call. If you need multiple calls, pages can quickly become very sluggish.

The recommended solution is to use Celery. Celery is a task queueing system which allows you to run the API requests outside of the request, response cycle.

Step 1 - Install Celery

Step 2 - Enable Tasks

# use celery for storing friends and likes
FACEBOOK_CELERY_STORE = True
# use celery for extending tokens
FACEBOOK_CELERY_TOKEN_EXTEND = True

When writing your own Facebook functionality you will see a big speedup by using @facebook_required_lazy instead of @facebook_required

Contributing and Running tests

Tests are run from within the example project. You can run them yourself as follows:

install from git

facebook_example/manage.py test django_facebook

Vagrant

A vagrant development setup is included in the GIT repo. Assuming you have vagrant installed, simply type the following in your shell:

# First get a fresh Django-Facebook checkout
git clone [email protected]:tschellenbach/Django-facebook.git django-facebook

# Go to the directory:
cd django-facebook

# Currently Vagrant is only support on branch `five`, so until this has been merged you need to switch branches:
git checkout five

# Time to start Vagrant (grab a cup of coffee after this command, it'll take a while) :)
vagrant up

# Finally done?
vagrant ssh
python manage.py runserver 0:8080

To have a working Django Facebook example up and running at 192.168.50.42:8000/facebook/example/. For the facebook login to work simply map that ip to vagrant.mellowmorning.com (Since Facebook checks the domain)

You can run the test suite by typing:

python manage.py test django_facebook

Django Jobs

Do you also see the beauty in clean code? Are you experienced with high scalability web apps? Currently we're looking for additional talent over at our Amsterdam office. Feel free to drop me a line at my personal email for more information: thierryschellenbach[at]gmail.com