<commit_before>######################################################################
Django Facebook by <NAME> (`mellowmorning.com <http://www.mellowmorning.com/>`_)
######################################################################

.. image:: 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 <http://www.fashiolista.com/intro_wide_minimal/>`_)

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 <http://www.mellowmorning.com/>`_

Further demos and tutorials will soon be available on `django-facebook.com <http://www.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 <http://www.facebook.com/developers/createapp.php>`_. 

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.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)


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<commit_msg>updated docs for signals and get_user_model<commit_after>######################################################################
Django Facebook by <NAME> (`mellowmorning.com <http://www.mellowmorning.com/>`_)
######################################################################

.. image:: 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 <http://www.fashiolista.com/intro_wide_minimal/>`_)

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 <http://www.mellowmorning.com/>`_

Further demos and tutorials will soon be available on `django-facebook.com <http://www.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 <http://www.facebook.com/developers/createapp.php>`_. 

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
{'fraction_non_alphanumeric': 0.07956388227581686, 'fraction_numerical': 0.001656143256391678, 'mean_word_length': 4.153627311522048, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 31, 'https://': 2, 'lorem ipsum': 0, 'www.': 14, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 80, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5120080', 'n_tokens_mistral': 7687, 'n_tokens_neox': 7257, 'n_words': 3240}