Building a real-time chat messaging application can be daunting and time-consuming for project and development teams. One reason is that the backend and frontend infrastructures must handle many aspects, like security and scalability. To build the Python app, we will use Stream's API for chat to handle WebSocket connections and other heavy lifting using Go, Raft, and RocksDB.
Prerequisites
To follow along and complete this tutorial, you should download and install the following technologies and tools on your Mac or Windows computer.
- An IDE: You can follow this tutorial using any IDE. However, to edit the Python and Django files, you should preferably use VS Code or Pycharm.
- Command line tool: For installing Python and other packages.
- Python and Django: For handling user authentication and authorization.
- Stream Chat React: An API for chat that uses Go, Raft, and - RocksDB to handle WebSocket connections and other heavy lifting.
- Stream Dashboard: To provide an app secret and API key to be used later in this tutorial.
Get the Source Code
Find the codebase of this tutorial on GitHub and follow the few instructions in the repository to clone and install the sample project. Also, check out and make sure have all the requirements under the Prerequisites section, and let's start coding! 🤓.
Step 1: Create a Chat Demo UI
Before diving into the Django and Python chat, let's create a React frontend, so that we have something nice and visual to look at. Our demo chat app is shownin the above preview. Open any command line tool you prefer and enter the following commands.
1234brew install node # skip if installed npm create vite@latest chat-frontend cd chat-frontend npm add stream-chat-react
To display the demo Reach chat UI, ensure you have installed the latest version of Node.js. As seen above, we initialize a new React project using Vite build tool npm create vite@latest chat-frontend
. Then, in the folder the project generates, we install the Stream Chat SDK for React npm add stream-chat-react
with NPM. You may also use yarn to initialize the project and install the chat SDK.
Launch the newly created project in an IDE like VS Code and replace the content App component App.tsx with the following sample code.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748// App.tsx import React from "react"; import { Chat, Channel, ChannelHeader, Thread, Window } from "stream-chat-react"; import { MessageList, MessageInput } from "stream-chat-react"; import { StreamChat } from "stream-chat"; import "stream-chat-react/dist/css/index.css"; const chatClient = new StreamChat("qk4nn7rpcn75"); // Demo Stream Key const userToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1za3ktOSJ9.mhikC6HPqPKoCP4aHHfuH9dFgPQ2Fth5QoRAfolJjC4"; // Demo Stream Token chatClient.setUser( { id: "cool-sky-9", name: "Cool sky", image: "https://getstream.io/random_svg/?id=cool-sky-9&name=Cool+sky" }, userToken ); const channel = chatClient.channel("messaging", "godevs", { // image and name are required, however, you can add custom fields image: "https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png", name: "Talk about Go" }); const App = () => ( <Chat client={chatClient} theme={"messaging light"}> <Channel channel={channel}> <Window> <ChannelHeader /> <MessageList /> <MessageInput /> </Window> <Thread /> </Channel> </Chat> ); export default App;
To summarize the sample code, we import Stream's chat SDK, which we just installed, and its reusable chat components. Then, we create an instance of the SDK's chat client and initialize it with a hard-coded user token. The token must be generated from a server for a production web application. You can also use your Stream dashboard's API key to create a token using the Stream's token generator service for testing. Sign up for a free account to get started.
Next, we should start the development server to see our chat demo live in the browser. Open the integrated Terminal in VS Code. cd
into the chat-frontend root folder and execute the following command to run the development server.
npm run dev
You will then see information like the one in the image below inside the Terminal window, along with a link to open the app with your local host.
Open the localhost’s http://localhost:5173/ to see a functional React messaging application supporting media upload, reactions, threads, replies, and more.
Step 2: Configure Python and Django
In this section, we will download and install Python and Django and set up a virtual environment to run the app. If you have already installed Python 3, you may skip the steps outlined below. Please note that if you are working on macOS, the operating system comes with a default installation of Python 2. We are not using this older version of Python in this tutorial. We should install Python 3 and set it up. First, check the version of Python on your machine with:
python --version # Windows
python3 --version # macOS
If Python 3 is not installed, you should download and install the latest version.
Create a Virtual Environment
The virtual environment and Django do not install along with the default Python installation. Therefore, we need to install them using pip, a dependency manager, and a package installer for Python. Let's use it to install a virtual environment for the app.
First, open your command line environment and enter the command:
pip install pipenv # Windows
pip3 install pipenv # macOS
Now, we should activate the Python 3 interpreter to use the app's virtual environment with the following; else, we will encounter an error when we run the app:
pipenv shell
Install Django
Let's cd
into the project's root folder and install Django with:
pipenv install django
Initialize a New Django Project
Now that we have Django installed, we can create a new project using:
django-admin startproject mychat .
The command above will create a new directory and the Django project inside it.
Run the App in the Virtual Environment
To run the virtual environment, open a new Terminal window in VS Code or use your command line environment to run the following in the mychat folder:
python manage.py runserver
Alternatively, we can run the virtual environment with Django Admin django-admin runserver
. Before running this command, ensure django-admin
knows about the project settings.
Let's configure it in VS Code. First, we need to get the path of the virtual environment. The path can be obtained with:
pipenv --venv
The above command will give a path similar to:
/Users/amosgyamfi/.local/share/virtualenvs/mychat-2pHymnq_
Copy the path and go to VS Code. Select View -> Command Palette... and search for Python Interpreter. Add a new one and paste the path above. Now that django-admin
knows about the project settings, go ahead and run the app using:
django-admin runserver
You will now see a preview similar to this one.
Step 3: Add User Authentication and Authorization
From the previous step, we have seen that our app is running successfully with Django. This section aims to authenticate and authorize a user against the Django backend. Let's follow the few steps here to create a user.
- Run
python manage.py migrate
to ask the Django backend to apply any pending database migrations. - Create an admin or super user
python manage.py createsuperuser
. This step requires a username, email, and password. You can leave the username field blank to log in with the user name on your machine.
- Keep the virtual environment running with
python manage.py runserver
. - When you see the above message Superuser created successfully after running
python manage.py createsuperuser
, you can log in with this URL http://localhost:8000/admin/.
Voila! 👏. You should see the Django admin screen below.
Step 4: Integrate React with Django
This section will integrate React with the Django project using a Django Rest Framework package. To make everything work successfully, we will need to create endpoints for:
- User Signup
- User Login
We could build those ourselves. However, a package called Djoser has already solved this problem. It configures the necessary API endpoints for user registration, login, password reset, etc.
To install Djoser, use the following snippet:
pip install djangorestframework djoser
If you get an error on macOS after running the command above, prepend sudo
to the snippet.
Then, edit urls.py and change the file to contain:
123456789// urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('auth/', include('djoser.urls')), path('auth/', include('djoser.urls.authtoken')), ]
Once complete, edit settings.py and make the following changes:
123456789101112131415161718// settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'djoser', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', ) }
For more on the API endpoints that Djoser exposes, have a look at djoser sample usage.
Now, let’s go ahead and test the registration endpoint:
curl -X POST http://127.0.0.1:8000/auth/users/ --data 'username=djoser&password=alpine12'
You will get back the following result in the command line:
{"email":"","username":"djoser","id":2}%
Step 5: Generate Tokens To Access Stream's Chat Server
Now, we need to customize the Djoser views to generate tokens for Stream. Let's get started by organizing our files a bit to create a chat app folder in our project (make sure that you are in the correct directory):
1python manage.py startapp auth
Install Stream Chat
We now have a new Django app. So, we can use pip install stream-chat
to add Stream Chat to the project.
After a successful installation, you will see a message similar to:
1Successfully installed aiodns-3.2.0 aiofile-3.8.8 aiohttp-3.9.5 aiosignal-1.3.1 attrs-23.2.0 caio-0.9.13 frozenlist-1.4.1 multidict-6.0.5 pycares-4.4.0 stream-chat-4.15.0 yarl-1.9.4
Create a Custom Serializer
Add a new Python file serializers.py in the auth folder with the following logic:
12345678910111213141516171819// serializers.py from djoser.serializers import TokenSerializer from rest_framework import serializers from djoser.conf import settings as djoser_settings from stream_chat import StreamChat from django.conf import settings class StreamTokenSerializer(TokenSerializer): stream_token = serializers.SerializerMethodField() class Meta: model = djoser_settings.TOKEN_MODEL fields = ('auth_token','stream_token') def get_stream_token(self, obj): client = StreamChat(api_key=settings.STREAM_API_KEY, api_secret=settings.STREAM_API_SECRET) token = client.create_token(obj.user.id) return token
Update the settings.py file to use the custom serializer by adding the following:
1234567STREAM_API_KEY = ‘YOUR_STREAM_API_KEY’ # https://getstream.io/dashboard/ STREAM_API_SECRET = ‘YOUR_STREAM_API_SECRET’ DJOSER = { 'SERIALIZERS': { 'token': 'auth.serializers.StreamTokenSerializer', } }
Create a new chat app in your Stream’s dashboard and copy your API key and the app’s secret to fill in the placeholders in the code snippet above, similar to this image.
Apply any pending database migrations by running the following:
python manage.py migrate
To verify that it works, hit the login endpoint with a POST request:
curl -X POST http://127.0.0.1:8000/auth/token/login/ --data 'username=djoser&password=alpine12'
Running the command above returns the auth_token
and stream_token
fields.
Note: If the curl
snippet fails to return the auth_token
and stream_token
, quit the server, rerun it with python manage.py runserver
, and try again.
Step 6: Integrate Auth
Adding an authentication later to the front end is essential for obvious reasons. In our case, it’s beneficial because we can fetch a user token from the backend API (powered by Python) and dynamically use it when sending messages.
First, install the Cross-Origin Resource Sharing (CORS) middleware package for Django to handle the server headers:
pip install django-cors-headers
Then, modify your settings.py to reference the djors-cors-header
middleware:
12345678910111213//settings.py INSTALLED_APPS = ( ... 'corsheaders', ... ) MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', ... ]
Still in the settings.py file, add the following:
CORS_ORIGIN_ALLOW_ALL = True
The above means any website can request the Django application, regardless of origin.
The next step requires a few modifications to the React front end. To start, you should ensure that you have all of the dependencies installed via yarn
or npm
:
npm add axios react-dom react-router-dom
- Axios is an HTTP client for Node.js.
- React Dom: A package serving as an entry point to the DOM and server renderers for React.
- React Router Dom: Contains bindings for using React Router in web apps.
Next, create the following files within your src directory of the chat-frontend folder:
Then, update the content of the App.js or App.jsx file with the following sample code.
1234567891011121314151617181920/*App.js*/ import React from "react"; import { BrowserRouter as Router, Switch } from "react-router-dom"; import Chat from "./Chat"; import Login from "./Login"; import UnauthedRoute from "./UnauthedRoute"; import AuthedRoute from "./AuthedRoute"; const App = () => ( <Router> <Switch> <UnauthedRoute path="/auth/login" component={Login} /> <AuthedRoute path="/" component={Chat} /> </Switch> </Router> ); export default App;
Be sure to replace YOUR_STREAM_APP_ID with a valid Stream App ID in the Chat.js file. The App ID can be found on the dashboard.
Restart your front-end application to hit the auth wall! Then, enter your email and password. A token will be requested and stored in local storage.
If you encounter a Switch error in your App.js, remove the react-router-dom package and install version 5.2.0.
12npm uninstall react-router-dom npm install react-router-dom@5.2.0
Step 7: Send a Message From the Python Chat Server
Occasionally, you will want to write to the chat API using your backend Python-based server. Here’s a quick management command that you can use:
Verify that the installed apps look like this in settings.py:
123456789101112INSTALLED_APPS = [ 'corsheaders', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'djoser', ]
Next, create the directory chat/management/commands. In that directory, add a file called broadcast.py with this content.
You can now try posting a message to the chat like this:
python manage.py broadcast --message hello
And you should see a response like this:
Final Thoughts
Hopefully, you enjoyed this tutorial on building a Python chat application!
For an interactive tour of Stream Chat, please have a look at our API Tutorial. Visit the React Components docs to learn more about the Chat SDK. Finally, we offer various SDKs for popular languages and frameworks if you want to build chat on top of Stream.