These days, it seems like Twitter is ubiquitous. Politicians, actors, parents — you name it — are using the social networking medium. Clients are not only demanding Web applications that are Twitter-enabled but that also have a slick Web 2.0 look to them, which is only achieved through Ajax. Enter Django and jQuery.
Figure 1. Twitter panel displaying recent tweets
I highly recommend going through the Django tutorial before commencing work on this. You will also need a solid JavaScript foundation. It goes without saying that you will need a Twitter account and must know the lingo, such as what a tweet is. Your arsenal should contain Python, Django, jQuery, and the python-twitter wrapper. See Resources for links.
You will also need the sqlite3 database, included with Python, for containing the session data; the Twitter infrastructure will save everything else. But, as an improvement on this application, you could certainly integrate a more sophisticated database structure to keep statistics, copies of tweets, or what's on your Twitter account on your own server, for example. This article also assumes that you're working on Linux®.
I tested the sample application with Python V2.5.2. Python is installed by default on most Linux machines; if you don't have Python installed, see Resources for information on downloading and installing the language.
Twitter's data is exposed to the public through two APIs: the search API and the RESTful API. (The Twitter FAQ mentions future plans for a single API.) A REST Web service is a Web service implemented in HTTP that follows REST principals (see Resources for more information).
Installing the python-twitter wrapper
The final component you need is python-twitter, which is "a python wrapper around the Twitter API and the twitter data model," according to the project site. There are several libraries for interfacing with Twitter's services in many languages — anything from Ruby to Eiffel. Currently, there are five libraries for interfacing Python with Twitter: Python-twitter by DeWitt Clinton, python-twyt by Andrew Price, twitty-twister by Dustin Sallings, twython by Ryan McGrath, and Tweepy by Josh Roesslein.
The python-twitter library requires the dependency simplejson (see Resources). After you download simplejson, install it by issuing the commands shown in Listing 1.
Listing 1. Commands for installing simplejson
tar -zxvf simplejson-2.0.9.tar.gz cd simplejson-2.0.9 sudo python setup.py build sudo python setup.py install |
If you prefer to use the egg package, you can use the command sudo
easy_install simplejson-2.0.9-py2.5-win32.egg.
Now, you can install python-twitter. After you download the package, execute the commands shown in Listing 2.
Listing 2. Commands for installing python-twitter
tar -zxvf python-twitter-0.6.tar.gz cd python-twitter-0.6 sudo python setup.py build sudo python setup.py install |
Next on the installation list is Django, a powerful Python Web framework. The sample application in this article was written with V1.1.1. The installation is just as easy as simplejson and python-twitter. After downloading the package, enter the commands shown in Listing 3 in any terminal.
Listing 3. Commands for installing Django
tar -zxvf Django-1.1.1.tar.gz cd Django-1.1.1 sudo python setup.py build sudo python setup.py install |
Verify that Django is on your path by trying the command
$ django-admin --version. If everything went as
planned, you're ready to start coding.
Now that you have installed python-twitter, you can explore its capabilities.
To access the library, use the command import twitter.
The twitter module provides wrappers for the
Twitter data model and the API. There are three data model classes:
twitter.Status, twitter.User, and
twitter.DirectMessage. All API calls return an object of one
of these classes. To access the API, make an instance of
twitter.Api() (notice that the first letter is capitalized).
Creating an instance without any arguments to the constructor is valid, but you're
limited to method calls that don't require a login. To have login access, use the
following code:
import twitter api = twitter.Api(username='yourUserName', password='yourPassword') |
With an instantiated Api object, you can get your
followers, people you are following, and statuses (tweets); post your current
status; etc. For example, to get a list of a user's statuses, call
statuses = api.GetUserTimeline(), which returns a list
of twitter.Status objects. To create another list with
the text (strings) of your tweets, you could use list comprehension: >>>print [s.text for s in statuses].
Table 1 lists classes and methods you will be using
in your Web application. For the full documentation, use the pydocs — $ pydoc twitter.Api, for example — or visit the
python-twitter docs page (see Resources).
Table 1. Some useful python-twitter API methods
| Method name | Returns | Description |
|---|---|---|
GetUserTimeline() | List of twitter.Status objects | Get all tweets for a user |
GetFriends() | List of twitter.User objects | Get a list of followers |
PostUpdate() | A single twitter.Status | Post a tweet |
To be more specific, you're not just using the jQuery core but also the jQuery UI, which provides widgets, themes, and animation. Head over to the ThemeRoller page, and in the left pane, click the Gallery tab. Choose a theme you like (I used Cupertino for the sample application), then click Download below the theme name. Doing so links to the actual download page; choose the current (stable) version, which at the time of this writing was 1.7.2 for jQuery V1.3+.
There is no installation process; just extract the ThemeRoller file and place the correct directories/files in the right place. You're also welcome to create your own theme if you wish, but for the sake of brevity, I used one of the pre-rolled themes.
Next, you need to create a new Django project. Use the command django-admin startproject pytweetproj where pytweetproj is the name used for the project throughout this article. Feel free to use another name, but be careful to use that name consistently throughout
your project. Change to the pytweetproj directory. To start the Django Web server,
at the command line, type python manage.py runserver, open a Web browser, and navigate to http://127.0.0.1:8000. You should get
a page that says,"It worked!" If at any time you want to stop or restart the
server, press Ctrl+C to kill the process. Don't use the development server for
production. When you've finished development on your project, move it over to a secure production
server, such as Apache.
While in the root project directory, create a subdirectory called resources, which will contain your CSS file, JavaScript files, and any other media. From wherever you extracted the previously downloaded ThemeRoller file, move or copy the css and js directories (extracted from the ThemeRoller ZIP file), as well as the jQuery core to the resources directories.
With your preferred text editor, open the settings.py file and change it to match the settings provided in Listing 4.
Listing 4. Django settings
# Django settings for pytweetproj project.
import os
APPLICATION_DIR = os.path.dirname( globals()[ '__file__' ] )
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
)
MANAGERS = ADMINS
# we'll use sqlite3 for caching
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = 'session.db'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# if you won't be using internationalization, better to keep
# it false for speed
USE_I18N = False
MEDIA_ROOT = os.path.join( APPLICATION_DIR, 'resources' )
MEDIA_URL = 'http://localhost:8000/resources/'
ADMIN_MEDIA_PREFIX = '/media/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = '=y^moj$+yfgwy2kc7^oexnl-f6(b#rkvvhq6c-ckks9_c#$35'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
# 'django.template.loaders.eggs.load_template_source',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
ROOT_URLCONF = 'pytweetproj.urls'
TEMPLATE_DIRS = (
os.path.join( APPLICATION_DIR, 'templates' ),
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'twitterPanel',
)
# added for sessions
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
|
To get the path of the current working directory in an operating system-independent
manner, use os.path.dirname( globals()[ '__file__' ] ) to
set the application directory. You use the same method to set the path to the
resources directory, as well as the TEMPLATE_DIR. It's also necessary to set the MEDIA_URL to http://localhost:8000/resources/.
You will be using sqlite3, a database included in Python. You will also need to set the
DATABASE_ENGINE, DATABASE_NAME, and the ROOT_URLCONF variables. Notice that
INSTALLED_APPS contains a value called twitterPanel, which
isn't created yet: You'll create that Django application next. Invoke the command
python manage.py syncdb to create the session database.
To create the twitterPanel application, use django-admin startapp twitterPanel and type cd to change into the newly created module directory: twitterPanel. In the twitterPanel directory, create another directory called templates, which will contain the Django templates.
With your favorite text editor, open the file url.py in the root of your project and change the code to match Listing 5. This file maps URLs to callback functions.
Listing 5. Root URL settings
from django.conf.urls.defaults import *
from django.conf import settings
urlpatterns = patterns('',
( r'^resources/(?P<path>.*)$',
'django.views.static.serve',
{ 'document_root': settings.MEDIA_ROOT } ),
( r'^twitterPanel/', include( 'twitterPanel.urls' ) ),
)
|
The first mapping in urlpatterns defines a match for statically
served resources or media — for example, image files. Because you are using
the Django development server, to serve your static content, you use the
django.views.static.serve() view. The second mapping
includes the URL patterns found in the twitterPanel
application. Open the url.py file found under twitterPanel (don't confuse that url.py
with the one in root) and add the code in Listing 6.
Listing 6. Twitter panel URLs
from django.conf.urls.defaults import *
from twitterPanel.views import *
urlpatterns = patterns( '',
url( r'^$', index, name = 'twitterPanel_index' ),
url( r'^panel/$', panel, name = 'twitterPanel_panel' ),
url( r'^update/$', update, name = 'twitterPanel_update' ),
)
|
You will create just three views: index, panel, and update. Notice that you will not add views to the root project — only to the Twitter Panel application. Open the view.py file found in the twitterPanel directory and add the imports in Listing 7 to the top of the file.
Listing 7. Twitter panel view imports
from django.shortcuts import render_to_response from django.template.context import RequestContext import twitter |
The render_to_response() method is a Django
shortcut for rendering a template with a specific context and returns an
HttpResponse object. The RequestContext
is a Django context with a few differences from the regular
django.template.Context. Specifically, it
accepts an HttpRequest object, and it automatically
populates the context with variables found in the
TEMPLATE_CONTEXT_PROCESSORS setting.
The first view method, index(), should look like Listing
8.
Listing 8. The
index view
def index(request):
template = 'index.html'
userName = request.POST.get( 'userTxt' )
password = request.POST.get( 'passwordTxt' )
if userName is not None and password is not None:
try:
api = twitter.Api( username = userName, password = password)
# just grab the first 5 tweets
statuses = api.GetUserTimeline()[0:5]
# limit to just the first 120
following = api.GetFriends()[0:120]
except NameError, e:
print "unable to login"
else:
statuses = {}
following = False
# place values in session
request.session['statuses'] = statuses
request.session['following'] = following
request.session['userName'] = userName
request.session['password'] = password
data = {
'statuses' : statuses,
'following' : following,
}
return render_to_response(template, data,
context_instance = RequestContext(request))
|
The template, index.html, hasn't been written yet. For the moment, just remember
that you have two HTML elements: a text box for entering the user name and a
password input. The data is sent to the view through the POST
method. If a user name and password are entered, you instantiate a
twitter.Api object and retrieve the first five tweets of
the logged-in user, as well as the first 120 people you're following. The statuses,
friends, user name, and password are all stored in the session for retrieval later
from other parts of the program.
The second view method, panel(), is much shorter. It's shown
in Listing 9.
Listing 9. The
panel view
def panel(request):
template = 'panel.html'
data = {
'statuses' : request.session['statuses'],
'following' : request.session['following']
}
return render_to_response(template, data,
context_instance = RequestContext(request))
|
Here, you use the panel.html template, also nonexistent as of yet. The
panel is where all the action will be going on
after you're logged in — in other words, where the tweets are displayed,
updates get done, and your friends are displayed. More on that in a little bit. For
the moment, all you're doing here is getting some data from the session, then doing
a render_and_response. In contrast, the third view
method, update, is a bit more complex. See
Listing 10.
Listing 10. The update view
def update(request):
template = 'panel.html'
userName = request.session['userName']
password = request.session['password']
try:
api = twitter.Api( username = request.session['userName'],
password = request.session['password'])
api.PostUpdate(request.POST.get('updateTextArea'))
updated = True
statuses = api.GetUserTimeline()[0:5] # reload the statuses
except NameError, e:
print "unable to login"
updated = False
data = {
'userName' : request.session['userName'],
'password' : request.session['password'],
'updated' : updated,
'statuses' : statuses
}
return render_to_response(template, data,
context_instance = RequestContext(request))
|
The user name and password are taken from the session, used to instantiate another
twitter.Api object, then use the api
object to post an update to the account. The statuses are then reloaded.
Within twitterPanel/templates, create a file called index.html and open it. Fill it with the code in Listing 11.
Listing 11. The index template
<html>
<head>
<title>Sample Python-Twitter Application</title>
<link type="text/css"
href="{{MEDIA_URL}}css/cupertino/jquery-ui-1.7.2.custom.css"
rel="stylesheet" />
<script type="text/javascript"
src="{{MEDIA_URL}}js/jquery-1.3.2.min.js"></script>
<script type="text/javascript"
src="{{MEDIA_URL}}js/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript">
$(function(){
// Dialog
$('#dialog').dialog({
autoOpen: false,
width: 400,
buttons: {
"Ok": function() {
$(this).dialog("close");
$.post('{% url twitterPanel_index %}', $("#loginForm").serialize());
$( '#panel' ).html( ' ' ).load( '{% url twitterPanel_panel %}' )
$( '#dialog_link' ).fadeOut(1500);
$( '#demoTitle' ).fadeOut(1500);
},
"Cancel": function() {
$(this).dialog("close");
}
}
});
// Dialog Link
$('#dialog_link').click(function(){
$('#dialog').dialog('open');
return false;
});
//hover states on the static widgets
$('#dialog_link, ul#icons li').hover(
function() { $(this).addClass('ui-state-hover'); },
function() { $(this).removeClass('ui-state-hover'); }
);
});
</script>
<style type="text/css">
body{ font: 62.5% "Trebuchet MS", sans-serif; margin: 50px;}
.demoHeaders { margin-top: 2em; }
#dialog_link {padding: .4em 1em .4em 20px;
text-decoration:none; position: relative;}
#dialog_link span.ui-icon {
margin: 0 5px 0 0;position: absolute;
left: .2em;top: 50%;margin-top: -8px;}
ul#icons {margin: 0; padding: 0;}
ul#icons li {
margin: 2px; position: relative; padding: 4px 0;
cursor: pointer; float: left; list-style: none;}
ul#icons span.ui-icon {float: left; margin: 0 4px;}
</style>
</head>
<body>
<h2 id="demoTitle" class="demoHeaders">PyTwitter Demo</h2>
<p>
<a href="#" id="dialog_link" class="ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-newwin"></span>Start Demo
</a>
</p>
<div style="position: relative; width: 96%; height: 200px; padding:1% 4%;
overflow:hidden;" class="fakewindowcontain">
</div>
<!-- ui-dialog -->
<div id="dialog" title="Login" >
<p>
<form action="#" name="loginForm" id="loginForm" method="POST">
<table>
<tr>
<td>user</td> <td><input type="text" name="userTxt" id="userTxt"/></td>
</tr>
<tr>
<td>password</td>
<td><input type="password" name="passwordTxt" id="passwordTxt"/></td>
</tr>
</table>
</form>
</p>
</div>
<!-- only show if logged in -->
<!-- Accordion -->
<div id="panel" style="position: absolute; top: 2%; left:2%;
width:600px; visibility:visible;">
</div>
</body>
</html>
|
Figure 2 displays the start of the application: a jQuery UI button.
Figure 2. jQuery UI button
This button calls the Login window shown in Figure 3.
Figure 3. The Login window
Let's dissect the code in Listing 11. First, you can tell the
browser where the CSS, JavaScript, and jQuery files are found using the
{{MEDIA_URL}}. When Django renders the template, it
substitutes {{MEDIA_URL}} with the actual path.
Inside the header, add your own JavaScript. The dollar sign ($)
is an alias for a jQuery instance. A jQuery shortcut
for document.getElementById('name') is
$('#name'). For example, you define a jQuery UI
element dialog using a <div>
tag, and then call the .dialog() method to create the
jQuery window. Inside, you add two buttons: OK and Cancel.
Cancel closes the window, whereas OK performs two actions:
It closes the window, then posts to the server. If the data that the index view
receives is the correct credentials, you get back the tweets and followers data.
Then, the window button and title fade out, and the Twitter panel fades in.
The magic line here is $( '#panel' ).html( ' ' ).load( '{% url twitterPanel_panel
%}' ), which loads the external Django template panel.html. The Twitter panel is a
jQuery UI accordion widget. Listing 12 shows the code
for the panel template. Save the code into panel.html inside within twitterPanel/templates.
Listing 12. The Twitter panel template
<script type="text/javascript">
$(function(){
$("#main").accordion({
header: "h3",
autoHeight: true
})
.hide()
.fadeIn(1500);
$('#updateTextArea').keyup(function(){
// text used for non-input elements. Var() is used for input elements
var tweetLength = $('#updateTextArea').val().length;
$('#charCount').text( 140 - tweetLength );
});
$('#updateBtn').click(function(){
if($('#updateTextArea').val().length <= 140){
// submit
$.post('{% url twitterPanel_update %}', $("#updateForm").serialize());
$("#updateStatus").text("last update: " + $('#updateTextArea').val());
// clear text area
$('#updateTextArea').val("");
// reset counter too
$('#charCount').text( "140" );
}
return false;
});
});
</script>
<div id="main">
<div>
<h3><a href="#">My Recent Tweets</a></h3>
<div>
{% if statuses %}
{% for s in statuses %}
<p style="border-top:1px dashed #f00; margin-top:1em;
padding-top:1em font: 80% 'Trebuchet MS', sans-serif;">
{{ s.text }}
</p>
{% endfor %}
{% else %}
No tweets found
{% endif %}
</div>
</div>
<div>
<h3><a href="#">Update Status</a></h3>
<div>
<form action="#" id="updateForm" name="updateForm" method="POST">
<textarea id="updateTextArea" name="updateTextArea" rows=2 cols=70 />
<button id="updateBtn" class="ui-state-default ui-corner-all">Update</button>
</form>
<div id="charCount" name="charCount" value=140>140</div>
<div id="updateStatus" name="updateStatus"><!-- update message here --></div>
</div>
</div>
<div>
<h3><a href="#">Following</a></h3>
<div>
{% if following %}
{% for f in following %}
<img src="{{ f.GetProfileImageUrl }}" width=28 height=28 />
{% endfor %}
{% else %}
following variable is empty
{% endif %}
</div>
</div>
</div>
|
Figure 4 shows the Twitter panel with the Update Status tab.
Figure 4. The Twitter panel displaying the Update Status tab
You name the accordion widget "main," and this is where all the action is once you're logged in. Inside the accordion, you have three tabs: My Recent Tweets, Update Status, and Following, as shown in Figure 5.
Figure 5. The Twitter panel, displaying the Following tab
The first tab displays just the first five tweets. If the status
object isn't empty, Django loops through each status
object and displays the corresponding text. Otherwise, a "No tweets found" message
is printed inside the tab.
The second tab, Update Status, contains an HTML form with a text area and
button. Under the form is a <div> called
charCount, followed by another <div>
called updateStatus. Update Status
is given an onclick event; the message length is tested
to make sure it's less than the 140-character limit and, if so, uses the jQuery
post method to send to the update view the update text,
which takes care of the rest. The latest tweet is then displayed on the page.
Just for fun, I've added some JavaScript for counting the number of characters left in the tweet. Remember, Twitter has a 140-character limit per tweet. The way it works is, when a key is released, the number of characters found in the update text box is subtracted from 140. The character count is then updated on the page.
The third tab in the Twitter panel, Following, first checks whether the
following object is not null. If so, just like the
My Recent Tweets tab, it loops through each user object. Each user
has a profile image URL: You stick that value inside the src
attribute of an <image> tag. The result is that
each user you're "following" is displayed in the third tab.
Now that all the pieces are in place, start the Django server and go to http://127.0.0.1:8000/twitterPanel. You should see a jQuery UI button for logging in. After clicking the button, the Login window appears. Type your twitter credentials, and the Twitter panel should fade in.
Now that you've looked at the demo, you've probably noticed how much effect the jQuery UI adds to the dynamic feel of the application. Django also makes it easy to handle the Python back end and templating.
Other things you could do to improve on the application include adding proper validation to the login process, error windows, or a list of your followers; sending direct tweets; and searching for tweets. Of course, feel free to use your creativity, as well.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample code | os-social-twitter-pytweetproj.zip | 160KB | HTTP |
Information about download methods
Learn
-
Learn about RESTful
applications.
-
Check out the Twitter API
documentation to learn everything you need to know about the Twitter API.
-
To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
-
Stay current with developerWorks' Technical events and webcasts.
-
Follow developerWorks on Twitter.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products, as well as our most popular articles and tutorials.
-
The My developerWorks community is an example of a successful general community that covers a wide variety of topics.
-
Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
-
Download Python, find documentation,
and take the Python tutorial. Then download the python-twitter wrapper.
-
Download Django, jQuery, and the jQuery UI.
-
Be sure to download the simplejson
dependency for the python-twitter wrapper.
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download
IBM product evaluation versions
or explore
the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from
DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
-
Participate in developerWorks blogs and get involved in the developerWorks community.





