Build the future of communications.
Start building for free

How to Build Chat into Django Applications with Twilio Programmable Chat

django-dark

Looking to build a realtime chat app? Building this from scratch requires thinking about lots of concerns at once. How should you model your users? What about different channels and different access levels? How about showing which users are online and when they start typing a message? There’s these questions and a lot more to answer when building a quality chat app.

That’s where Twilio Programmable Chat comes in. This awesome service helps abstract away the groundwork involved in building realtime chat applications. Chat comes with support for basic chat features such as channels, users, roles and permissions. There are also many other advanced features that you can add incrementally to your app.

We will create a chat room application, where users can chat on different topics in different rooms, typically known as “channels”. Our application will be simplified and through it we will explore how to build out a chat application using the Django web framework. The chat functionality will be fully powered by Twilio Chat.

Development Environment

To get through the tutorial, these are the tools we’ll need:

Time to go over each of these setup steps one by one.

Python 3

The Python community is moving to Python 3 and it supports all of libraries that we will use. You can check your Python version by running the following command in your terminal.

python --version

You can download the installer from the official website if you do not yet have it on your system. Once Python is installed on your system and running the python command takes you to the Python prompt, we can proceed to the next step. At the time of writing, the latest version is Python 3.6.5.

Virtual Environment Setup

Virtualenv is a nifty tool that will help us set up isolated Python environments along with their application dependencies. Go ahead and follow the installation instructions if you do not already have it installed.

Once it is installed, we need to choose a location for storing our virtual environments. I usually store mine in ~/.virtualenvs. Once you’ve decided on a location, then create the virtualenv with this command:

virtualenv -p python3 ~/virtualenvs/django-chat

This creates the virtualenv in ~/virtualenvs and sets Python 3 as the default Python version inside the virtualenv.
To activate the environment, we should run on the command line:

source ~/virtualenvs/django-chat/bin/activate

Once the virtual environment is activated, we should see the name of our env in the command prompt e.g. (django-chat)$.

Install Dependencies with pip

pip is a tool for installing Python dependencies. With our virtualenv activated, install the Django and Twilio libraries into our virtualenv:

pip install django==1.11.10 twilio==6.10.1

Our initial setup is now complete and we can start building the chat room app. Keep in mind that the virtualenv should stay activated for the remainder of the tutorial.

Build the Chat Room App Backend

We’ll kick things off by setting up the Django project. We first need to create a new Django project then switch directories to the newly created folder. We will run all future commands from the chatroom_app folder.

django-admin startproject chatroom_app
cd chatroom_app

In the Django project folder, we should now create a new Django app by running:

python manage.py startapp chat

This command will create a chat/ folder where all our Python code relating to the chat app should go. Change directories to get to the chatroom_app folder, where you’ll find a settings.py file. This is where we need to do some initial setup. We need to instruct Django to load the chat app in our project. This is configured in the INSTALLED_APPS setting.

In chatroom_app/settings.py, find INSTALLED_APPS and append 'chat.apps.ChatConfig' to it so it ends up like this:

# chatroom_app/settings.py

INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'chat.apps.ChatConfig',
]

This configuration indicates to Django that it should load the ChatConfig class from the chat/apps.py file. That should be enough to load our chat app along with the other inbuilt apps. We will now set up Twilio. Still in settings.py, we need to load in some environment variables that we’ll need later to connect to Twilio. We’ll get the actual credentials from Twilio later on, so don’t worry about them quite yet.

Add these settings at the bottom of the file beneath the STATIC_URL line and we’ll go through how to fill in each one shortly:

# chatroom_app/settings.py

TWILIO_ACCOUNT_SID = os.environ.get('TWILIO_ACCOUNT_SID', None)
TWILIO_API_KEY = os.environ.get('TWILIO_API_KEY', None)
TWILIO_API_SECRET = os.environ.get('TWILIO_API_SECRET', None)
TWILIO_CHAT_SERVICE_SID = os.environ.get('TWILIO_CHAT_SERVICE_SID', None)

To ease the process of loading in these environment variables, we’re going to create a .env file in the root Django project folder, and load the config from this file through the python-dotenv package.

Install the package by running in the terminal:

pip install python-dotenv

Then add the following to settings.py:

# chatroom_app/settings.py

# Add this import at the top of the file
from dotenv import load_dotenv

# Add this anywhere below the BASE_DIR setting
dotenv_path = os.path.join(BASE_DIR, '.env')
load_dotenv(dotenv_path)

With this in place, any settings we add to the .env file will be loaded in to the environment variables. You can copy the starter .env file from that we will then populate with our Twilio credentials in the GitHub repository.
Time to get the authorization settings from Twilio.

  1. Create an account with Twilio if you don’t already have one.
  2. Navigate to the dashboard and you’ll see an Account SID. Copy this and add it to the .env file as the TWILIO_ACCOUNT_SID setting.

  1. Head over to the Chat Services section and click on the Create new Chat Service button. You will be prompted for a name and once you enter that, click on Create

  1. You will be redirected to a page showing your app’s details. You will see a Service SID. Save this as the TWILIO_CHAT_SERVICE_SID setting in our .env file
  2. For the remaining settings, navigate to the API Keys page and click on the Create new API Key button. Give it a name, then click on Create API Key

  1. You will be navigated to a page showing your newly created credentials. Save the SID as the TWILIO_API_KEY and save the Secret as the TWILIO_API_SECRET environment variable.

With these settings in place, we can now proceed to write up the rest of our application. The first thing we need to address is creating the Django models. This is where we define what information from our app will be persisted in our database. For our case, we are going to need to store the available chat rooms in the database. For each room, we’ll store its name, description and slug.
This info will live inside chat/models.py. We should go up a directory and then cd into the chat folder to get to the file.

# chat/models.py

from django.db import models

class Room(models.Model):
    """Represents chat rooms that users can join"""
    name = models.CharField(max_length=30)
    description = models.CharField(max_length=100)
    slug = models.CharField(max_length=50)

    def __str__(self):
        """Returns human-readable representation of the model instance."""
        return self.name

With these changes made to the models, we need to tell Django to track these changes in order to eventually apply them to the database. Django tracks these changes through a migration, which is the link between our models and the database.

Therefore to create the migrations, we need to back up a directory to where manage.py is and run:

python manage.py makemigrations chat

This creates a file chat/migrations/0001_initial.py that will contain the changes that Django will apply to the database. To actually apply the changes, we need to run the migrate command to apply the newly created migration to the database.

python manage.py migrate

With this done, we can now use our models from Django to insert data in the database. We can create some rooms and save them to the database. We’ll need to use them later on. To do this, we’ll need to go into the interactive Python shell by running on the command line:

python manage.py shell

From here, we can create the room instances we need by running the following commands:

>>> from chat.models import Room
>>> Room.objects.create(name='General', slug='general', description="Stop by and say hi! Everyone's welcome")
>>> Room.objects.create(name='Random', slug='random', description="Random chit chat. Best place to just chill")
>>> Room.objects.create(name='Twilio Chat', slug='twilio-chat', description="Chat about... Twilio Programmable chat")

With the rooms created, we can now exit the shell by typing exit() on the Python prompt.
At this point we have a populated models.py file and some rooms stored in the database. This seems like a good time to run our app and confirm that there are no issues so far. We can do this by running the following terminal command:

python manage.py runserver

We can now see our app running on http://localhost:8000. We should see the Django default page saying “it worked”. In case you encounter any errors, you can go back and see if you missed any step we’ve been through so far.

In Django, views are responsible for fetching data from the database and providing this data to the templates for it to be displayed to the user.
We’re going to add 2 views:

  • A view to fetch all available rooms – We’ll use this to show all the rooms on the homepage
  • A view to fetch a single room’s details, given it’s slug – We’ll use this to populate the chat room with the room’s details

Add these lines to the chat/views.py file:

# chat/views.py

from .models import Room

def all_rooms(request):
    rooms = Room.objects.all()
    return render(request, 'chat/index.html', {'rooms': rooms})


def room_detail(request, slug):
    room = Room.objects.get(slug=slug)
    return render(request, 'chat/room_detail.html', {'room': room})

Let’s go over the views and what they do. The all_rooms view is responsible for fetching all the rooms from the database, and passing them to the chat/index.html template to be rendered. Inside the chat/index.html template, the rooms will be available as the rooms variable. This will be hooked up to the homepage URL as we will see later.

The room_details view, on the other hand, takes a slug, and uses that to fetch a specific room, which is then passed to the chat/room_detail.html template to be rendered. The slug is fetched from the URL, as we will also see shortly when defining the routes.

We’re done with the views, but we also need to define the route to use to access them.
Create a new file in the chat/ folder and name it urls.py. Keep in mind that this is a separate file from the urls.py file in the chatroom_app folder. Inside this file, add the following contents:

# chat/urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.all_rooms, name="all_rooms"),
    url(r'rooms/(?P<slug>[-\w]+)/$', views.room_detail, name="room_detail"),
]

The urls.py file is responsible for mapping a route to the corresponding view. The first pattern in the urlpatterns list designates the all_rooms view to handle the requests made to the root url of the chat app.

The second one instructs Django that any URL starting with /rooms/* should be handled by the room_detail view and it should pass the part after the rooms/ as the slug parameter to the view.

There’s one more thing left to do. The chat/urls.py file only handles URLs for the chat app, and not for the whole Django project. We need to add another entry to chatroom_app/urls.py pointing to the chat app’s URL entries and what route they need to be namespaced under.
Go up a folder and edit chatroom_app/urls.py to look as follows:

# chatroom_app/urls.py

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
   url(r'^admin/', admin.site.urls),
   url(r'^', include('chat.urls')),
]

Right now, accessing http://localhost:8000 should give us the following error:

TemplateDoesNotExist at /
chat/index.html

The error instructs us that we haven’t created the template yet. We can fix that now.

Django templates are used to build the HTML that we should eventually see and interact with on the screen.
In our views, we defined a couple of templates i.e. chat/index.html and chat/room_detail.html that we now need to create and fill out.

Under the chat/ folder, create a new folder called templates. Inside the templates folder, create another folder and name it chat. This is where Django expects to find the templates used by the chat app.  Inside the templates/chat/ folder, we can now create our actual templates: index.html and room_detail.html.

Add the following content to chat/templates/chat/index.html:

{% load static %}

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="shortcut icon" href="//www.twilio.com/marketing/bundles/marketing/img/favicons/favicon.ico">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" />
  <style>
    .rounded-edges {
      border-radius: 0.25rem;
    }
  </style>
  <title>All Chat Rooms</title>
</head>

<body>
  <section class="hero is-info">
    <div class="hero-body has-text-centered">
      <div class="container">
        <h1 class="title is-2">
          Twilio Chat
        </h1>
        <h2 class="subtitle is-5">
          An exploration into Twilio Programmable Chat.
          <br/> Join one of the rooms below to start your adventure
        </h2>
      </div>
    </div>
  </section>
  <section class="section">
    <div class="container">
      <div class="columns">
        {% for room in rooms %}
        <div class="column">
          <div class="card rounded-edges">
            <div class="card-content">
              <p class="title is-4">{{room.name}}</p>
              <div class="content">
                <p>
                  {{room.description}}
                </p>
                <a href="/rooms/{{room.slug}}" class="button">Join Room</a>
              </div>
            </div>
          </div>
        </div>
        {% endfor %}
      </div>
    </div>
  </section>
</body>
</html>

Let’s go through the most important changes we’ve made to our template:

  • We are using the Bulma CSS framework, which we’re loading from CDNJS to make our app look nicer. If you see us using some unfamiliar classes, they’re most likely from Bulma.
  • As you may recall in the all_rooms view, we fetched all the rooms and passed them to the template as rooms. Now that we can access the rooms, we loop over the rooms collection and display some details about the room i.e. the name, description and slug (link to an individual room)

If everything is working as expected, our web app’s homepage should look like this screenshot:


Note that if you had the server running, you need to restart it in order to load the newly created templates.

Now we can populate the other template i.e. room_detail.html in the same chat directory. This is the template for the page that you be shown once you click on any of the ‘Join Room’ links from the homepage. It will also be the room where the chat will happen.

It’s going to have the main chat area and a section showing the room’s details. This is the content we’re going to add to the template:

{% load static %}

<!DOCTYPE html>
<html>

<head>
  <title>{{room.name}} | Twilio Chat</title>
  <link rel="shortcut icon" href="//www.twilio.com/marketing/bundles/marketing/img/favicons/favicon.ico">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" />
  <link rel="stylesheet" href="{% static "chat/styles/room_detail.css" %}">
</head>

<body>
  <div class="container">
    <div class="columns">
      <div class="column is-three-quarters">
        <section>
          <div id="messages"></div>
          <form id="message-form">
            <div class="field">
              <label class="label">Message</label>
              <div class="control">
                <textarea class="textarea" id="message-input"placeholder="Your message here" rows="3" autofocus>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
{% load static %}
 
 
  </span><span class="crayon-i ">{{room.name}} | Twilio Chat</span><span class="crayon-r ">
  rel="shortcut icon" href="//www.twilio.com/marketing/bundles/marketing/img/favicons/favicon.ico">
  rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" />
  rel="stylesheet" href="{% static "chat/styles/room_detail.css" %}">
 
  
class="container">
    
class="columns">
      
class="column is-three-quarters">
        
          
id="messages">
          
id="message-form">
            
class="field">
              
              
class="control">
                
              
            
            
          
        
      
 
      
class="column sidebar">
        
class="float-right">
          

class="title">{{room.name}}

          

class="subtitle">

            {{room.description}}
          

        
      
 
    
  
 
  
  
  
  
Authors
Sign up and start building
Not ready yet? Talk to an expert.