Example Facebook application in Django

Check out the new site at https://rkblog.dev.

Facebook is well known social web site. For developers it offers rich API that allows making web apps integrated with the site.

Everything for developers can be found on developers.facebook.com. Available to users apps are located in apps directory. Usually users do some quizzes, publish their results and compare, comment with other friends.

facbk1

Facebook app can be writen in many languages like PHP, Python, Ruby, Perl, Java. Apps are hosted on your server, not on facebook. APIs for all of this can be found on the wiki, and some support is available on the forum.

For python developers there is PyFacebook library, which helps in using the Facebook API, and in making Django apps integrated with the site. The code can be obtained from GIT repository:

git clone git://github.com/sciyoshi/pyfacebook.git

Creating new app on Facebook

  • Go to App Developers and click on Set Up New Application
  • Enter a name for you app and accept the terms:
    facbk2
  • Next we can set up icons and description for the app. You can change them later.
    facbk3
  • After saving we will see a list of our apps. To make it available on Facebook - we have to make the app in Django.
    facbk4

Creating a Facebook integrated Django app with PyFacebook

We need a new or existing Django project. If you create a new one - set the basic configuration like database. If your done with that we can continue.
  • To create basic app for use with Facebook use djangofb.py from PyFacebook (you can copy it to the project folder):
    python djangofb.py startapp zalamka
    Creating Facebook application 'zalamka'...
    Writing /home/piotr/svn/0skala/biblioteka/zalamka/models.py...
    Writing /home/piotr/svn/0skala/biblioteka/zalamka/views.py...
    Writing /home/piotr/svn/0skala/biblioteka/zalamka/__init__.py...
    Writing /home/piotr/svn/0skala/biblioteka/zalamka/urls.py...
    Done!
    
    There are a couple of things you NEED to do before you can use this app:
    
     * Set FACEBOOK_API_KEY and FACEBOOK_SECRET_KEY to the appropriate values in settings.py
    
     * Add 'facebook.djangofb.FacebookMiddleware' to your MIDDLEWARE_CLASSES in settings.py
    
     * Add 'NAZWA_PROJEKTU.NAZWA_APLIKACJI' to your INSTALLED_APPS in settings.py
    
    The final step is to add (r'^biblioteka/', include('biblioteka.zalamka.urls')) to your urls.py, and then set your callback page in the application settings on Facebook to 'http://your.domain.com/biblioteka/'.
    
    Good luck!
    
    This script will make a Django app with some basic Facebook app skeleton, and also will instruct what you need to do more to make it work
  • Add to settings.py variables: FACEBOOK_API_KEY and FACEBOOK_SECRET_KEY and set your app API KEY and Secret Key (you can get if from your app list)
  • Add new middleware to MIDDLEWARE_CLASSES. Add facebook.djangofb.FacebookMiddleware
  • And finaly add this django app into INSTALLED_APPS. In my case it's PROJECT_NAME.zalamka
  • Next in urls.py add rule for the new app (I use bit different than the suggestion):
    (r'^zalamka/', include('zalamka.urls'))
  • Compared to the tutorial on facebook wiki - I didn't got "templates" folder in my app, so I copied it from the example in PyFacebook package (/examples/pyfacebook_sample). If we have templates folder we can add it to TEMPLATE_DIRS in settings.py.
  • Edit models.py of the app and change maxlength to max_length
  • Create tables:
    python manage.py syncdb
  • If you have public IP - you can use your local django development server to create and debug the app. If not - you have to push changes to the main server, and debug the app from there. For public IP we have to start the Django server on port 80, which need root/sudo permissions:
    python manage.py runserver 0.0.0.0:80
  • Then our project is available under http://Your_IP, and the facebook app in this example http://Your_IP/zalamka/.
  • Now edit app settings on Facebook, and go to "Canvas" tab. Set Canvas Callback URL to http://Your_IP/zalamka/, and Canvas Page URL to "zalamka" - this is the URL-name of the app that will be use on facebook. Also change Render method to FBML.
    facbk5
  • Now under http://apps.facebook.com/NAME/ you should see a basic Facebook app comming from your server:
    facbk6
    facbk7
    The basic app you see isn't anything useful, so it's time to make one.
  • In this app we are using FBML which is a set of extra HTML-like tags that allows easy integration with some facebook components (they can make forms, display comment boxes and so on).
  • My goal is to make an app that will show some pictures from a website demotywatory.pl (you can make the same for a lolcat site for example). The basic code that extracts the URLs and info I need looks like this:
    # -*- coding: utf-8 -*-
    from re import findall
    import urllib2
    
    opener = urllib2.build_opener()
    opener.addheaders = [('user-agent', 'Opera/9.64 (X11; Linux x86_64; U; en) Presto/2.1.1')]
    d = opener.open('http://www.demotywatory.pl')
    de = d.read()
    print findall('<div\sclass="demot_pic"><a\shref="(.*?)"><img\ssrc="(.*?)"\sclass="demot"\salt="(.*?)"\s/></a></div>', de)
    
    If it works I can move it to a Django view.
  • I my "zalamka" test app I have one view:
    # -*- coding: utf-8 -*-
    from re import findall
    import urllib2
    from os.path import isfile, getmtime, join
    from time import time
    
    from django.http import HttpResponse
    from django.shortcuts import render_to_response
    from models import User
    from django.conf import settings
    
    import facebook.djangofb as facebook
    
    @facebook.require_login()
    def canvas(request):
    	# POST - user submitted form
    	if request.POST and 'demot' in request.POST and len(request.POST['demot'].strip()) > 0:
    		uid = request.facebook.uid
    		request.facebook.feed.publishUserAction ('21106...TEMPLATE_ID', {'demot' : request.POST['demot']}, [], 1)
    		return request.facebook.redirect(request.facebook.get_url('profile', id=uid))
    	
    	# show the images
    	
    	cache_file = join(settings.MEDIA_ROOT, 'demotywator.cache')
    	if isfile(cache_file) and getmtime(cache_file) > time()-3600:
    		# use cached
    		de = open(cache_file).read()
    	else:
    		# get new content
    		try:
    			opener = urllib2.build_opener()
    			opener.addheaders = [('user-agent', 'Opera/9.64 (X11; Linux x86_64; U; en) Presto/2.1.1')]
    			d = opener.open('http://www.demotywatory.pl')
    			de = d.read()
    			cache = open(cache_file, 'w')
    			cache.write(de)
    			cache.close()
    		except:
    			# log this
    			de = ''
    	
    	demots =  findall('<div\sclass="demot_pic"><a\shref="(.*?)"><img\ssrc="(.*?)"\sclass="demot"\salt="(.*?)"\s/></a></div>', de)
    	name = request.facebook.users.getInfo([request.facebook.uid], ['first_name'])[0]['first_name']
    	return render_to_response('canvas.fbml', {'name': name, 'demots': demots})
    
    Skip request.POST for now. The rest of the code is basic - get the page and extract data. For better performance I cache the data for 1 hour:
    if isfile(cache_file) and getmtime(cache_file) > time()-3600:
    
    New thing is also request.facebook which allows us to use Facebooka API mapped to Python methods.
  • Used template canvas.fbml is a Django template, in which we can (but don't have to) use FBML. In my case it looks like this:
    <fb:header>
     It's so demotivating. <a href="http://demotywatory.pl">Demotywatory.pl</a> now on Facebook :(
    </fb:header>
    <style>
    .demot
    {
    margin-top:2px;
    padding:5px;
    background-color:black;width:490px;margin-left:10px;
    }
    .demot p
    {
    text-align:center;
    font-weight:bold;
    padding-left:20px;
    color:yellow;
    }
    </style>
    <div class="clearfix" style="border: 1px #d8dfea solid; padding: 10px; width:520px;margin: 0 auto 0 auto;">
     {% if demots %}
    	<div class="grayheader clearfix" style="text-align:center;">
    	{% for i in demots %}
    	<h3 style="margin-bottom:3px;margin-top:15px;background-color:black;color:white;padding:5px;width:490px;margin-left:10px;">{{ i.2 }}</h3>
    	<a href="{{ i.0 }}"><img src="{{ i.1 }}" alt="{{ i.2 }}" /></a><br />
    	<div class="demot"><p><img src="http://www.python.rk.edu.pl/site_media/zalamka.png" alt="" /> It's depressing, so I want to depress others</p>
    	
    	<fb:editor action="./" labelwidth="100">
    	<input type="hidden" value="{{ i.0 }}" name="demot" />
    	<fb:editor-buttonset>
    		<fb:editor-button value="Submit"/>
    	</fb:editor-buttonset>
    	</fb:editor>
    	
    	</div>
    	<br /><br />
    	{% endfor %}
    	</div>
    
      {% else %}
      	 <div class="grayheader clearfix" style="text-align:center;"><b>No pictures</b></div>
      {% endif %}
    <div style="text-align:center;">In this apps icons from famfamfam and Tango projects are used.</div>
    </div>
    
    FBML Tags start with fb:. In the template above I've set page header with fb:header, and made a HTML form with fb:editor (but I could use my own). In result I get:
    facbk10
  • Displaying content isn't enough. I want to allow users post infos about a picture on their profile/wall - for this purpose I've added the form. In the view the form is controlled by this code:
    if request.POST and 'demot' in request.POST and len(request.POST['demot'].strip()) > 0:
    		uid = request.facebook.uid
    		request.facebook.feed.publishUserAction ('TEMPLATE_ID', {'demot' : request.POST['demot']}, [], 1)
    		return request.facebook.redirect(request.facebook.get_url('profile', id=uid))
    
    feed.publishUserAction method takes few arg: id of registered template, dictionary with extra variable for the template, ID list of user friends to notify, and message type: 1 - one line, 2 - short.
  • To publish messages on the wall we can use templates, which need to be registered on Feed Template Console:
    facbk8
    Variables are passed in form {*name*}. Every template must start with {*actor*}, which inserts message autor name. If we use our own variables - we have to specify a test value in Sample Template Data. When we register the template we will get the template ID:
    facbk9
  • If we have the template ID we can use it to send the message. The app ends with redirecting the user to it's wall:
    request.facebook.feed.publishUserAction ('TEMPLATE ID', {'demot' : request.POST['demot']}, [], 1)
    return request.facebook.redirect(request.facebook.get_url('profile', id=uid))
    
    facbk11
The app is very simple. You can build more complex using the Facebook API, or make your website Facebook-friendly with Facebook Connect. The Facebook Connect APIs are Javascript/XFBML based and allow you to add components that allow users login using Facebook account, and comment content from your site on their walls. You can use a middleware or fbconnect to get cookie of a user that logged in with Facebook on your site (the Facebook login makes a cookie, which is used only by other facebook components).

For me the APIs that Facebook provie aren't the best thing on the net. One thing that there is no nice documentation for the PyFacebook (you have to look at the standard API docs). Second - if you go see an API description - there should be real code examples (expecialy for Connect), and linkt to things I could use also (for example you can add a comment on your website with XFBML or using JS API, but the docs on the JS API won't tell you that). Third: JavaScript API? JS making queries (FQL) ? It's hard to debug, hard to integrate with server-side websites. And some browsers don't render XFBML :) For me good API can be found at Flickr - clean REST API for read and write operations with various permissions that is managed by server-side language of your site.

RkBlog

Django web framework tutorials, 10 July 2009


Check out the new site at https://rkblog.dev.
Comment article
Comment article RkBlog main page Search RSS Contact