Bixly How-To: integrate django with facebook – part2

In the previous entry, “Bixly How-To: integrate django with facebook – part1”, we used the Facebook Javascript SDK to provide access to the Graph API for the user.

The Facebook Graph API accessed with the Python SDK and Javascript SDK provides a lot of operations with regards to accessing user information (e.g. access token, friends, news feed) and other tasks such as album creation and image upload. We will continue where we left off in part 1 of this 2-part tutorial. We encourage you to integrate Facebook’s Javascript SDK shown in part 1 first before proceeding below.

Including the Facebook’s Python SDK

Step 1: We first create a folder in the app folder called fbconnect. Download facebook.py from (link no longer exists) and store it in the fbconnect folder. We rename it to fbconnect.py for convenience. We need to create an empty __init__.py in the same directory so that django defines the folder as a package.

Step 2: We then create a file named fbutils.py in the same folder containing the code below.

import fbconnect
from settings import FB_APP_ID, FB_APP_SECRET

appid = FB_APP_ID
appsecret = FB_APP_SECRET

def connect(request):
	user = fbconnect.get_user_from_cookie(
			request.COOKIES, 
			appid, 
			appsecret)
	if user:
		fbgraph = fbconnect.GraphAPI(
			user["access_token"])
		return fbgraph, user["access_token"]
	return None, None

This code simply wraps fbconnect’s function get_user_from_cookie. If the user is logged in through Facebook, the get_user_from_cookie function returns a dictionary containing ’uid’ which is the user’s Facebook ID and ‘access_token’ which can be used to make authenticated requests to Facebook’s Graph API. When we call the connect function we created above, we’ll receive either the Facebook GraphAPI instance and the user access token when the user is logged in via Facebook or None, None otherwise.

When we have the user’s access token, we can easily perform Facebook API calls such as accessing the user’s information, image uploading, posting content in user’s walls, and creating and modifying events (provided that the user granted such permissions for the application).

Step 3: We modify the views.py code to have

	def index(request):	
	fbgraph,access_token = connect(request)

	context = {
		'access_token':access_token,			
		}

	return render_to_response('index.html', context, 
		context_instance=RequestContext(request))

Given that the connect function returns fbgraph object and the access token, we first include in the view the value of the Facebook access token of the user.

We then  display the access_token value after “Updated Time” in your template page.

<div id="other_information" style="display: none;">
	...
	Updated Time:  <span id="updated_time"></span><br />
	Access Token: {{access_token}}
</div>

Step 4: The Graph API of Facebook can also be accessed using the Python SDK provided. In our case, all we need to do is to use the fbgraph object provided by our connect function.

By using the python code fbgraph.get_object(‘me’), we get the same values as the javascript code FB.api(‘/me’). Notice that the only difference between them is syntax.They both access https://graph.facebook.com/me with the access token as the parameter. If you want to see the keys and values returned by the Graph API, view this in your web browser https://graph.facebook.com/me?access_token=ACCESS_TOKEN. 

Include the fbgraph.get_object(‘me’) codes in your views.py. It should look something like this.

def index(request):	
	fbgraph,access_token = connect(request)
	fbgraph_me = fbgraph.get_object('me')
	context = {
		'access_token':access_token,
		'fbgraph_me':fbgraph_me
		}
	return render_to_response('index.html',
		context,
		context_instance=RequestContext(request))

To see the dictionary value of the fbgraph_me variable we passed to the template, we add this line after the access token in index.html

FBGraph Me: <pre>{{fbgraph_me}}</pre>

Step 5: The Graph API also has the capability to display the user’s friends. To demonstrate this, we use fbgraph.get_connections(‘me’,’friends’) to get the list of friends of the user. The python code fbgraph.get_connections(‘me’,’friends’) returns a dictionary of the form

{u'data': [{
	u'name': u'Friend1Name', u'id': u'Friend1ID'}, 
	{u'name': u'Friend2Name', u'id': u'Friend2ID'}
	]}

We then include fbgraph_friends = fbgraph.get_connections(“me”, “friends”)[‘data’] in our views.py and we add the following code in our template page.

FBGraph Friends:<br />
{% for fbfriend in fbgraph_friends %}
	ID:{{fbfriend.id}} - {{fbfriend.name}}<br />
{% endfor %}

Step 6: We can also get the user’s news feed with the Graph API. By using fbgraph_newsfeed = fbgraph.get_connections(“me”, “home”), we get to a dictionary of the form

{
u'paging': 
	{
		u'next': <next value>, 
		u'previous': <previous value>
	}, 
u'data': 
	[
		{
			u'from': <from dictionary>, 
			u'privacy': <privacy dictionary>, 
			u'actions': [
				{
					u'link': <action link>, 
					u'name': <action name>
				}, 
				{
					u'link': <post link>, 
					u'name': <action name>
				}
			], 
			u'updated_time': <updated time>, 
			u'created_time': <created time>, 
			u'message': <message>, 
			u'type': <status>, 
			u'id': <post id>
		}, 
		{
			u'from': <from dictionary>, 
			u'privacy': <privacy dictionary>, 
			u'actions': [
				{
					u'link': <action link>, 
					u'name': <action name>
				}, 
				{
					u'link': <post link>, 
					u'name': <action name>
				}
			], 
			u'updated_time': <updated time>, 
			u'created_time': <created time>, 
			u'message': <message>, 
			u'type': <status>, 
			u'id': <post id>
		},  			  
	]
}

where each dictionary stored in the data list refers to one post in the user’s wall.

To display the posts in the user’s wall, we include fbgraph_newsfeed = fbgraph.get_connections(“me”, “home”)[‘data’] in our views.py and we then add the following code to our template page.

<br />FBGraph News Feed:<br />
{% for fbnews in fbgraph_newsfeed %}
	ID:{{fbnews.id}} - {{fbnews.message}}<br />
{% endfor %}

Step 7: Sometimes, obtaining the user’s photos is needed in the web application. This is also possible through Facebook’s Graph API. First we create a wrapper function in fbutils.py for the function fbgraph.request(‘me/albums’,args={‘access_token’:fb_access_token}) which returns a dictionary of data from Facebook. The wrapper function for obtaining the photo albums of the user will simply return a list containing an album’s name and id. The wrapper function is provided below.

def getAlbums(fbgraph,fb_access_token):
	response = fbgraph.request('me/albums',
		args={'access_token':fb_access_token})
	data = response['data']
	album_list = []
	for album in data:
		album_list.append({
			'id':album['id'],
			'name':album['name']})
	return album_list

The wrapper function above returns a dictionary with the form

[
	{
		'id': ,
		'name': 
	},
	{
		'id': ,
		'name': 
	},
]

Now we add the following lines of code in views.py to print the ids and names of each album of the user on the console.

fbgraph_albums = getAlbums(fbgraph, access_token)
for fbgraph_album in fbgraph_albums:
	print fbgraph_album['id'], fbgraph_album['name']

Given the ID of an album, using the GraphAPI, we can get the information of all the images in the specified album. We create another wrapper function in fbutils.py for the function fbgraph.request(‘%s/photos’%album_id,args={‘access_token’:fb_access_token}) which returns a dictionary of data from Facebook. The wrapper function for obtaining the photos of the album of the user will simply return a list containing urls of each image. The wrapper function is provided below.

def getPhotos(fbgraph,fb_access_token,album_id):
	response = fbgraph.request('%s/photos'%album_id,
		args={'access_token':fb_access_token})
	imagecollection = []
	for photo in response['data']:
		imagecollection.append(photo['picture'])
return imagecollection

To test the wrapper function above, we modify views.py and include the code below.

for fbgraph_album in fbgraph_albums:
	print fbgraph_album['id'], fbgraph_album['name']
	print getPhotos(fbgraph,
		access_token,
		fbgraph_album['id'])

The console should then have something like

<album 1 id>: <album 1 name>
[<url to photo 1 of album 1>, <url to photo 2 of album 1>, ...]
<album 2 id>: <album 2 name>
[<url to photo 1 of album 2>, <url to photo 2 of album 2>, ...]

To display all the photos in each album of the user, we modify views.py again to contain the code below.

fbgraph_photos = []
for fbgraph_album in fbgraph_albums:			
	fbgraph_photo_album_name = 
		fbgraph_album['name']
	fbgraph_photo_album_photos = 
		getPhotos(fbgraph,
			access_token,
			fbgraph_album['id'])						
	fbgraph_photos.append({
		'album_name':
			fbgraph_photo_album_name,
		'album_photos':
			fbgraph_photo_album_photos})

We also include the following code in the template page as well:

<br />FBGraph Photo Albums:<br />
{% for fbalbum in fbgraph_photos %}
	<br />{{fbalbum.album_name}}<br />
	{% for fbphoto in fbalbum.album_photos %}
		<a href="{{fbphoto}}" target="_blank">
			<img src="{{fbphoto}}" 
				width="100px" 
				height="100px"/>
		</a>
	{% empty %}
		No images available
	{% endfor %}
{% endfor %}

The code above simply displays all the images inside the album successively. Clicking on the images will open a new page containing the original Facebook photo.

Step 8: Access to the Graph API for each user depends on the permissions allowed for the application. It is advisable to check the allowed permissions for the app before trying to gain access to any specific user information or action. This is possible through fbgraph.get_connections(‘me’,”permissions”) which returns a dictionary of the form:

{'data':[{
	'read_stream': 1,
	'user_birthday': 1,
	...
	'friends_status': 1,
}]}

The dictionary returned by Facebook contains only the keys of the allowed permissions. To check if a permission has been allowed for a specific request, we may do the following:

fbgraph_permissions =  fbgraph.get_connections('me',"permissions")['data']
if key in fbgraph_permissions:
	#do something

Notes: There is a lot more to Facebook Graph API and Facebook Python SDK than what I have described here. Be sure to check out the documentation for all the rest of the features. For reference purposes, the codes are shown below.

#views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from fbconnect.fbutils import connect, getAlbums, getPhotos

def index(request):	
	fbgraph,access_token = connect(request)
	if fbgraph:
		fbgraph_me = fbgraph.get_object('me')
		fbgraph_friends = fbgraph.get_connections(
			"me", "friends")['data']
		fbgraph_newsfeed = fbgraph.get_connections(
			"me", "home")['data']
		fbgraph_albums = getAlbums(
			fbgraph,access_token)
		fbgraph_photos = []
		for fbgraph_album in fbgraph_albums:			
			fbgraph_photo_album_name = 
				fbgraph_album['name']
			fbgraph_photo_album_photos = getPhotos(
				fbgraph,
				access_token,
				fbgraph_album['id'])						
			fbgraph_photos.append({
			'album_name': 
				fbgraph_photo_album_name,
			'album_photos': 
				fbgraph_photo_album_photos})

		fbgraph_permissions =  fbgraph.get_connections(
			'me',"permissions")['data']

		context = {
			'access_token':access_token,
			'fbgraph_me':fbgraph_me,
			'fbgraph_friends':fbgraph_friends,
			'fbgraph_newsfeed':fbgraph_newsfeed,
			'fbgraph_photos':fbgraph_photos,
			'fbgraph_permissions':
				fbgraph_permissions,
			}
	else:
		context = {
			}
	return render_to_response('index.html',
		context,
		context_instance=RequestContext(request))
#index.html
{% load fbconnect %}
<html>
<head>
<!-- JS Files -->		
<script type="text/javascript" src="js/jquery.js"></script>

{% facebook_login_script %}

<!-- Document Ready functions -->
<script type="text/javascript">
//functions which are done when the document is ready
$(function(){									
	fbconnected(function(){
		// connected to facebook
		fblogin_success();				
	},function(){
		// not connected to facebook				
		fblogin(fblogin_success,fblogin_fail);
	});
});
</script>

<script type="text/javascript">
function fblogin_success(){
	//logged in user			
	FB.api('/me', function(response) {					
		$('#name').html(response.name);												
		$('#first_name').html(response.first_name);
		$('#last_name').html(response.last_name);
		$('#link').html(response.link);
		$('#birthday').html(response.birthday);
		$('#gender').html(response.gender);
		$('#timezone').html(response.timezone);
		$('#locale').html(response.locale);
		$('#verified').html(''+response.verified);
		$('#updated_time').html(response.updated_time);
		$('#other_information').show();				
	});

	$('#post_button').click(function(){
		var body = $('#post_box').val();
		FB.api('/me/feed', 'post', { message: body }, function(response) {
			if (!response || response.error) {
				alert('Your post was not published successfully');
			} else {
				alert('Your post "'+body+'" was published successfully');
			}
		});
	});

	$('#post_div').show();
}
function fblogin_fail(){
	//guest			
}
</script>
</head>
<body>
{% facebook_load_script %}
<div id="post_div" style="display:none">
Post something in your wall! <br />
<input id="post_box"/><button id="post_button">Submit</button>
</div><br />

<div>Hello 
<span id="name">Guest</span>!<br />
<div id="other_information" style="display: none;">
	First Name: <span id="first_name"></span><br />
	Last Name: <span id="last_name"></span><br />
	Link: <span id="link"></span><br />
	Birthday: <span id="birthday"></span><br />
	Gender: <span id="gender"></span><br />
	Timezone: <span id="timezone"></span><br />
	Locale: <span id="locale"></span><br />
	Verified: <span id="verified"></span><br />
	Updated Time: <span id="updated_time"></span><br />
	Access Token: {{access_token}}<br />
	FBGraph Me: <pre>{{fbgraph_me}}</pre><br />
	<br />FBGraph Friends:<br />
	{% for fbfriend in fbgraph_friends %}
		ID:{{fbfriend.id}} - {{fbfriend.name}}<br />
	{% endfor %}
	<br />FBGraph News Feed:<br />
	{% for fbnews in fbgraph_newsfeed %}
		ID:{{fbnews.id}} - {{fbnews.message}}<br />
	{% endfor %}
	<br />FBGraph Photo Albums:<br />
	{% for fbalbum in fbgraph_photos %}
		<br />{{fbalbum.album_name}}<br />
		{% for fbphoto in fbalbum.album_photos %}
			<a href="{{fbphoto}}" target="_blank"><img src="{{fbphoto}}" width="100px" height="100px"/></a>
		{% empty %}
			No images available
		{% endfor %}
	{% endfor %}
	<br />
	FBGraph Permissions: <pre>{{fbgraph_permissions}}</pre>
</div>
</div>

</body>
</html>
#fbutils.py
import fbconnect
from settings import FB_APP_ID, FB_APP_SECRET

appid = FB_APP_ID
appsecret = FB_APP_SECRET

def connect(request):
	user = fbconnect.get_user_from_cookie(
		request.COOKIES, appid, appsecret)
	if user:
		fbgraph = fbconnect.GraphAPI(
			user["access_token"])
		return fbgraph, user["access_token"]
	return None, None

def getAlbums(fbgraph,fb_access_token):
	response = fbgraph.request('me/albums',
		args={'access_token':fb_access_token})
	data = response['data']
	album_list = []
	for album in data:
		album_list.append({
			'id':album['id'],
			'name':album['name']})
	return album_list

def getPhotos(fbgraph,fb_access_token,album_id):
	response = fbgraph.request('%s/photos'%album_id,
		args={'access_token':fb_access_token})

	imagecollection = []

	for photo in response['data']:
		imagecollection.append(photo['picture'])

	return imagecollection

References: