Django Facebook by Thierry Schellenbach (mellowmorning.com)
New in 4.0
4.0 introduces improved compatiblity for the offline access migration. I highly recommend upgrading. These are some of the awesome new features:
- Standalone registration support (we no longer require django userena and django registration)
- Local image storage is now easy to setup and enabled by default
- Automatic reauthentication for expired tokens (Great for the offline access migration)
- Travis - CI tested <http://travis-ci.org/#!/tschellenbach/Django-facebook/>
Backwards incompatible changes:
- You need to explicitly send connect_facebook=1 to connect an existing account to your Facebook account
- You need to specify a custom backend when using Django registration or Userena. See the section on django userena and django registration support.
- You should make sure your media settings are ok to support image upload
The docs can also be found at: http://django-facebook.rtfd.org/
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. After registration it 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
I've built it for my startup Fashiolista.com and it's currently used in production there with thousands of signups per day. For a demo of the signup flow have a look at Fashiolista's landing page (fashiolista.com)
Before you get started building your application, know that contributions are very welcome. Seriously, if you see a bug or think of an improvement just open a pull request or issue. Feel free to contact me if you have questions.
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)
Download 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',
The full setting on a new django 1.4 app looks like this:
TEMPLATE_CONTEXT_PROCESSORS = ( 'django_facebook.context_processors.facebook', '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.contrib.messages.context_processors.messages', )
Add this to your AUTHENTICATION_BACKENDS
setting:
'django_facebook.auth_backends.FacebookBackend',
The full setting on a new django 1.4 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
Django uses a custom Profile model to store additional user information. Read more about this topic in the Django Docs.
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.
Right now you should have a working registration/connect/login in flow available at /facebook/connect/ Test if everything is working and ensure you didn't miss a step somewhere. If you encounter any difficulties please open an issue.
Registration Backends
Django Facebook uses registration backends to integrate with various registration frameworks. No registration backend is required. However if you want to integrate with django registration, django userena or a custom backend you need to point us in the right direction.
Django Registration support Simply set your facebook registration backend to your preferred backend.
FACEBOOK_REGISTRATION_BACKEND = 'registration.backends.default.DefaultBackend'
Django Userena support
We recommend using Django Userena. It seems easier to work with than Django Registration. Both are supported and good packages though. To use django userena simply point to the userena compatability layer.
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.
Old Django Registration Support
Even older version of Django Registration are supported. Simply point to the old django registration compatability backend.
FACEBOOK_REGISTRATION_BACKEND = 'django_facebook.registration_backends.OldDjangoRegistrationBackend'
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.
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.
Customize and integrate into your site
Not 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" /> </form>
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.contrib.auth.models import User 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=User)
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_profile_class def pre_facebook_update(sender, profile, facebook_data, \*\*kwargs): profile.facebook_information_updated = datetime.datetime.now() # Manipulate facebook_data here profile_class = get_profile_class() signals.facebook_pre_update.connect(pre_facebook_update, sender=profile_class)
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_profile_class def post_facebook_update(sender, profile, facebook_data, \*\*kwargs): # Do other stuff profile_class = get_profile_class() signals.facebook_post_update.connect(post_facebook_update, sender=profile_class)
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_profile_class def post_friends(sender, user, friends, current_friends, inserted_friends, \*\*kwargs): # Do other stuff profile_class = get_profile_class() facebook_post_store_friends.connect(post_friends, sender=profile_class)
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_profile_class def post_likes(sender, user, likes, current_likes, inserted_likes, \*\*kwargs): # Do other stuff profile_class = get_profile_class() facebook_post_store_likes.connect(post_likes, sender=profile_class)
The Facebook App center requires your app to authenticate the user's experience when landing on your site. It already provides you with the required token. (Honestly I think it's a really weird user experience.) But to get it working you must use the following url for site url (App -> Settings -> Basic -> Website with Facebook Login)
http://www.mydomain.com/facebook/connect/?facebook_login=1
Note that the given tokens can't be used for local testing. (Facebook checks the url for which the authorization was given.)
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
Todo:
- Canvas utility functions (abstracting javascript redirects) (in progress)
- Token expiration detection (check out https://github.com/aidaeology/Django-facebook/commit/8585ce223e18cf19f410b4e6aa56b1478913162e for an older version of this concept)
- Improve testing
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