Building Ribbit in Django

After implementing our Twitter-clone, Ribbit, in plain PHP and Rails, it's time to introduce the next walk-through: Python! In this tutorial, we'll rebuild Ribbit using Django. Without further delay, let's get started!

Step 0 - Bootstrapping

As of the time of this writing, Django 1.4 supports Python 2.5 to 2.7.3. Before proceeding, make sure that you have the apt version by executing python -v in the terminal. Note that Python 2.7.3 is preferred. All throughout this tutorial, we'll use pip as our package manager and virtualenv to set up the Virtual Environments. To install these, fire up the terminal and execute the following commands as root

With our Virtual Environment, set up and activated (your command prompt should be changed to reflect the environmen's name), let's move on to installing the dependencies for the project. Apart from Django, we'll be using South to handle the database migrations. We'll use pip to install both of them by executing. Do note that from here on, we'll be doing everything inside the virtualenv. As such, ensure that it's activated before proceeding.

pip install Django South

With all of the dependencies set up, we're ready to move on to creating a new Django Project.

Step 1 - Creating the Project and the Ribbit App

We'll begin by creating a new Django project and our app. cd into your preferred directory and run:

PROJECT_PATH will store the location of the directory in which settings.py is stored. This will allow us to use relative paths for future constants. LOGIN_URL, as the name suggests, designates that the root of our site will be the URL to Login.

Moving on, let's configure the database. For the development evironment, sqlite3 is an ideal choice. To do so, edit the DATABASES constant with the following values:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': os.path.join(PROJECT_PATH, 'database.db'), # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}

Django finds the static files from the directory mentioned in the STATIC_ROOT constant and routes requests to the files to the path specified in STATIC_URL. Configure them so that they reflect the following:

The syncdb command will create the required tables and create the superuser account. Since we're using South for migrations, we make the initial migration for the app using the syntax schemamigration <app_name> --initial and apply it with python manage.py migrate ribbit_app

Let's start our development server to ensure everything is working correctly.

python manage.py runserver

If everything's fine indeed, you should be greeted with the following page when you visit http://localhost:8000

Before moving on to the next step, let's commit our changes to the repo.

git add .
git commit -m 'Created app and configured settings'

Step 2 - Base Template and Static Files

Following on from the interface tutorial, download the assets and place them within the ribbit_app/static directory. We need to make some edits to style.less for this tutorial. Let's begin with adding some styles for the flash.

Next, let's update the width of the input elements and add the error class for the same. Note that the code below contains only the styles that are required to be added or updated. The remaining code remains untouched.

Next, let's create the base template, which will be inherited by all the other templates. Django uses it's own templating engine (like ERB or Jade). Define the template in ribbit/templates/base.html with the following content:

In the above markup, {{ STATIC_URL }} prints the path for the static url defined in settings.py. Another feature is the use of blocks. All the content of the blocks is inherited to the sub-classes of the base template, and will not be overwritten unless the block is explicitly redefined in them. This provides us with some flexibility to place the navigation links at the header and replace it with the login form if the user isn't signed in. We're also using a block with an if condition to check if any of the flash variables are not empty and render the messages appropriately.

Alright! Time to make another commit:

git add .
git commit -m 'Created base template'

Step 3 - Creating the Models

One of the best things about Django is that it includes quite a few models and forms, which can be overridden to suite many purposes. For our application, we'll use the User model and add a few properties to it by creating a UserProfile Model. Further, to manage the ribbits, we'll create a Ribbit Model as well. The User model provided by Django includes fields to store the username, password, first and last names and email address (with validation) along with many others. I suggest you to have a look at the API to know about the all fields supported by default. Add the following code for models in ribbit_app/models.py.

Let's start with the Ribbit Model. The attributes include a CharField with maximum length of 140 characters to store the content, a ForeignKey to the User model (so that we have a relation between the two models) and a DateTimeField which is automatically populated with the time when the instance of the model is saved.

Moving on to the UserProfile Model, we've a OneToOne field that defines a One to One relation with the User Model and a ManyToMany field to implement the follows/followed_by relation. The related_name parameter allows us to use the relation backwards using a name of our choice. We've also set symmetrical to False to ensure that if User A follows B then User B doesn't automatically follow A. We've also defined a function to get the link to the gravatar image based upon the user's url and a property to get (if the UserProfile exists for the user) or create one when we use the syntax <user_object>.profile. This allows us to fetch the properties of UserProfile quite easily. Here's an example of how you might use the ORM to get the users that a given User follows and is followed by:

superUser = User.object.get(id=1)
superUser.profile.follows.all() # Will return an iterator of UserProfile instances of all users that superUser follows
superUse.profile.followed_by.all() # Will return an iterator of UserProfile instances of all users that follow superUser

Now that our models are defined, let's generate the migrations and apply them:

Step 4 - Creating Forms

Django allows us to create forms so that we can easily validate the data accepted by the user for irregularities. We'll create a custom form for the Ribbit Model andcreate a form that inherits UserCreationForm provided by default to manage the registration. For managing the authentication, we'll extend the AuthenticationForm provided by default in Django. Let's create a new file ribbit_app/forms.py and add the imports.

In the form above, we've explicitly set some of the fields as mandatory by passing in required=True. Further, I've added the placeholder attribute to the different widgets used by the forms. A class named error is also added to the fields that contain errors. This is done in the is_valid() function. Finally, in the Meta class, we can specify the order in which we want our form fields to render and set the model against which the form should be validated.

For the index view, we first check if the user is logged in or not and render the templates, accordingly. The querysets ribbits_self and ribbits_buddies are merged with the | operator in the above code. Also, we check if an instance of a form has been passed to the method (in the function definition) and if not we create a new one. This allows us to pass around form instances to the appropriate templates and render the errors.

Let's proceed with editing the 'home.html' template which will be used to show the index page for anonymous users. In the ribbit/templates/home.html file, add the following code.

In the template, we inherit the base template defined before, render the authentication and sign up forms by overriding the login block. A neat thing about Django is that it makes CSRF Protection quite easy! All you need to do is add a csrf_token in every form you use in the template.

Let's move on to the buddies.html template, which will show the Buddies' Ribbit page. Edit ribbit/templates/buddies.html and add the following code:

In this template, we provide the parent template i.e. base.html with the value of username so that the navigation link for the logged in User's profile renders correctly. We're also using an instance of RibbitForm to accept new Ribbits and looping over and showing the current ribbits by our buddies.

With the templates finished, let's move on and write the code to log in/out the user. Add the following code to ribbit_app/views.py

The views for login expect a HTTP POST request for the login (since the form's method is POST). It validates the form and, if successful, logins the user using the login() method which starts the session and then redirects to the root url. If the validation fails, we pass the instance of the auth_form received from the user to the index function and list the errors, whereas, if the request isn't POST then the user is redirected to the root url.

The logout view is relatively simpler. It utilizes the logout() function in Django which deletes the session and logs the user out followed by redirecting to the root url.

We now need to write the view to sign up and register a user. Append the following code to ribbit_app/views.py.

Similar to the login view, the signup view expects a POST request as well and redirects to the root url if the check fails. If the Sign Up form is valid, the user is saved to the database, authenticated, logged in and then redirected to the home page. Otherwise, we call the index function and pass in the instance of user_form submitted by the user to list out the errors.

Let's check our progress by starting the server and testing the views we've written so far manually.

python manage.py runserver

Let's visit our Development Server and try registering a new user. If all goes well, you should be presented with the Buddies' Ribbits page. We can logout and reauthenticate the newly created user to check if the sign in functions work as expected.

Time to commit the changes!

git add .
git commit -m 'Implemented User Login and Sign Up'

Step 6 - Accepting new Ribbits and Listing Public Ribbits

In the buddies.html template we created before, the ribbit_form was submitted to /submit. Let's edit ribbit/urls.py and add the route for the form and the page to list all the public ribbits.

The view uses the @login_required decorator, which executes the function only if the user is authenticated; else, the user is redirected to the path specified in LOGIN_URL constant in the settings. If the form validation is successful, we manually set the user to the one contained in the session and then save the records. After the database commit, the user is redirected to the path specified in next_url field which is a hidden form field we manually entered in the template for this purpose. The value of next_url is passed along in the views that render the Ribbit Form.

Moving on, let's write the view to list the last 10 Public Ribbits. Append the following in ribbit_app/views.py

In the public view, we query the database for the last 10 ribbits by slicing the queryset to the last 10 elements. The form along with the ribbits are then rendered to the template. Let's create ribbit/templates/public.html for this view

While looping over the ribbit objects, the template uses the timesince template tag to automatically determine the time difference between the ribbit creation date and current time, and prints it in a Twitter-like way.

Ensuring that the development server is running, create a new ribbit and have a look at the Public Ribbits page to ensure everything is fine.

An interesting route above is the one to direct to a specific user's profile. <?P<username> captures the username queried via GET, and \w{0,30} asserts that the maximum length for a username is 30 characters:

Next, we'll proceed with writing the view to render User Profiles. Append the following in `ribbit_app/views.py'.

This view is perhaps the most interesting of all that we've covered so far. We start by ensuring that only logged in users are able to view profiles. In the routes we defined in ribbit/urls.py, we wrote one to capture the username. This captured parameter is automatically called along with the request object in the users view. We come across two options for this view:

A username is passed to the url to render a specific user's profile

No username is passed which implies the user wants to view all profiles

We begin by checking if a username is passed and is not empty. Then, we try to fetch a User object for the corresponding username. Note the use of a try catch block in the code above. We simply raise a Http404 exception provided by Django to redirect to the default 404 template. Next, we need to check if the profile requested is of the logged in user or one of his buddies. If so, we don't need to render a follow link in the profile since the relation is already established. Otherwise, we pass along the follow parameter in the view to print the Follow link.

Moving on to the second point, if no username is given in the url, we fetch a list of all the users and use the annotate() function to add a ribbit_count attribute to all objects, which stores the number of Ribbits made by each user in the queryset. This allows us to use something along the lines of <user_object>.ribbit_count to fetch the Ribbit Count of the user.

Getting the latest Ribbit by each user is a bit tricky. We use Python's built in map() function for this and call get_latest() to all the elements of users queryset. The get_latest() function is defined in the code above and makes use of a backward relation on the User<-->Ribbit relation. For instance user.ribbit_set.all() would return all the ribbits by the user. We order the ribbits by id in descending order and slice the first element. The code is enclosed in a try catch block to catch the exception if no ribbits are created by the user. We're then making use of Python's zip() function to link up each element of both iterators (users and ribbits) so that we have a tuple with User Object and Latest Ribbit pair. We then pass along this zipped object along with the forms to the template. Let's write our last view that will accept the request to follow a user

In the view above, we get the value of the follow parameter, passed by POST. If the id is set we check if a user exists and add the relation, else, we catch an ObjectDoesNotExist exception and redirect the user to the page that lists all User Profiles.

We're done with the views here. Let's write the remaining two templates required to render the user profiles. Open your text editor and edit ribbit/templates/profiles.html.

To list the user along with his last ribbit, we use a common python construct to iterate over a list of tuples: for user, ribbit in obj. Inside the loop we print the information about the user along with his ribbit stats. Notice the use of a backward relation in {{ user.profile.followed_by.count }}. followed_by is the related name we set up while defining the ManyToManyField attribute for the UserProfile Model.

Finally, let's write the template to list a specific user's profile. Write the following code in ribbit/templates/user.html.

As in the buddies.html template, we pass the username of the logged in template to the parent template using the {% with %} construct. Next, we display the user's profile and display the follow link only if the follow variable is set to True. After that, we list all the ribbits created by the user by iterating over the ribbits variable.

We're finally done with all the views and templates. Browse around all the links and try following dummy users and explore the Twitter-clone you've just created.

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'ribbit', # Or path to database file if using sqlite3.
'USER': 'username', # Not used with sqlite3.
'PASSWORD': 'password', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}

At the end of the file, append the following so that Heroku can figure out the database settings.

Conclusion

We're finally done with Ribbit in Django! This tutorial was quite long, indeed, and the application still has much more potential that can be implemented. I hope that, if you are new to Django, this article has encouraged you to dig more deeply.

Feel free to play along with my deployment at Heroku. If you have any questions, I'd be glad to answer and all questions.

I'm a freelance developer with a penchant for Open Source Software and have experience working in Python, PHP and Javascript. I'm currently pursuing an undergrad degree at BITS Pilani, KK Birla Goa Campus. Feel free to contact me on @gnarula94 or connect with me on LinkedIn.