In my last article I talked about WebSockets and how we can establish a web socket connection from the client side/JavaScript. Today, we will begin our journey to write a simple chat app, which will be really helpful in demonstrating how web sockets work and how we can build real-time Django apps.
As we already know, in a typical Django project the client makes an HTTP request, Django calls the view that is responsible for managing this request and returns a response back to the client.
This communication is pretty standard. But ever since Django has introduced ASGI and started supporting it natively, we are able to write Django applications with asynchronous code in addition to synchronous code. Django Channels which let's us work with web sockets is also built on ASGI.
Before getting any further, let's talk about ASGI and its predecessor WSGI.
WSGI - WSGI is the Web Server Gateway Interface. It is a specification that describes how a web server communicates with web applications, and how web applications can be chained together to process one request. It's like a mediator for carrying out interaction between a web server and a python application.
ASGI - ASGI (Asynchronous Server Gateway Interface) is a spiritual successor to WSGI, intended to provide a standard interface between async-capable Python web servers, frameworks, and applications.
So, the difference is that WSGI provides a standard for running synchronous apps while ASGI let us run asynchronous apps allowing us to work with more advanced protocols like web sockets where it can send and receive multiple data over a single connection.
If ASGI is enabled in our app, Django will let us write asynchronous views, and manage async enabled requests. But to write async applications that work with WebSockets, we need to use Django Channels.
If you haven't already, check out my last article on WebSockets before continuing.
Django Channels
Django channels goes beyond HTTP and support other protocols such as web sockets and is built on ASGI.
The underlying implementations we are going to see in channels are pretty much similar to the regular HTTP views that we are used to working with. In order to handle a WebSocket connection, channels has routing.py and consumers.py.
- routing.py is like urls.py
- consumers.py is like views.py
When a request or new socket comes in, Channels will follow its routing table, then find the right consumer for that incoming connection, and start up a copy of it. More on this later.
Set up and Installation
1) Set up a virtual environment
2) Install Django then create a project
pip install django
django-admin startproject config .
3) Install channels
pip install channels
4) Add channels to your list of installed apps in the settings.
settings.py
INSTALLED_APPS = [
# ...
'channels',
]
5) Go to your project's asgi.py file and adjust it as follows to wrap the Django ASGI application:
asgi.py
import os
import django
from channels.http import AsgiHandler
from channels.routing import ProtocolTypeRouter
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
django.setup()
application = ProtocolTypeRouter({
"http": AsgiHandler(),
# We will add WebSocket protocol later, but for now it's just HTTP.
})
6) And finally, set your ASGI_APPLICATION setting to point to that routing object as your root application:
settings.py
ASGI_APPLICATION = "config.asgi.application"
Perfect! Now channels has taken over the runserver command and an ASGI/Channels development server will be run from this point forward.
Check this by running the development server python manage.py runserver
and you will see the following:
Getting started
The best way to get started with channels and ASGI is by creating a simple chat app. Therefore, after you are done with the basic set up and installation, go ahead and create a Django app.
python manage.py startapp chat
Add it to the list of installed apps in your settings.
settings.py
INSTALLED_APPS = [
# ...
'chat',
]
Alright, for this simple chat app we are going to have 2 views.
- The first view we are going to create is the index view. This is what allows users to type in the chat room they want to join.
- The second view is the room view that lets users in the same connection to see messages posted in that chat room.
In this tutorial, we will create the first view which is the index view.
That being said, let's head over to our chat app and create a templates directory. Within the templates directory, create another directory named chat, and within that create a file named index.html.
Put the following code inside the index.html fle.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
What chat room would you like to enter?<br>
<input id="room-name-input" type="text" size="100"><br>
<input id="room-name-submit" type="button" value="Enter">
<script>
document.querySelector('#room-name-input').focus();
document.querySelector('#room-name-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#room-name-submit').click();
}
};
document.querySelector('#room-name-submit').onclick = function(e) {
var roomName = document.querySelector('#room-name-input').value;
window.location.pathname = '/chat/' + roomName + '/';
};
</script>
</body>
</html>
- The script in the above html file is pretty straight forward. It's going to listen to events i.e. when the user presses enter or the submit button after typing in the chat room, he/she will be redirected to the room view http://127.0.0.1:8000/chat/roomName/.
Now, let's create the view that is associated with the above template.
views.py
from django.shortcuts import render
def index(request):
return render(request, 'chat/index.html')
Now, Create urls.py module inside the chat app and map the index
view to the url patterns.
chat/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
- Go to the project's urls.py file and include the chat app's url.
config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('chat/', include('chat.urls')),
]
Time to check if it's working
python manage.py runserver
Go to http://127.0.0.1:8000/chat/ in your browser and voila you have the index page. Type in a chat room and you will get redirected to the room view which we haven't created yet so it'll display a “Page not found” error page.
Reference - https://channels.readthedocs.io/en/stable/
That's it for today. In an upcoming tutorial we will create the room view and start writing consumers.
Top comments (3)
Please friends... I don't know if the bug is due to version difference from django or from channels... My AsyncWebsocketConsumer refuses to send objects through the socket... I feel my code is very correct tho.
Here are links to two of my demo projects facing the same case.
I'll be very glad if someone helps me out.
github.com/eoguh/djandochat
github.com/eoguh/djangoVchat_mysite
waiting for part 3.
Thanks, you can check it out here