В этой статье мы разберём как сделать чат на Python Django, тут будет только самое базовое, что нужно знать про это.
Примечание:
Также крайне рекомендуется перед прочтением, прочитать статью «Django библиотека channels для WebSocket», так как в этой мы не будем показывать настройку и основы работы с библиотекой channels а её мы и будем использовать для реализации WebSocket на Django.
Настройка проекта:
Первым делом нужно всё настроить, для этого нужно создать виртуальное окружение, тут можете посмотреть статью про это «Создание Virtual Environments Python».
После того как сделали виртуальное окружение и создали проект на Django, можете скачать саму библиотеку channels и ещё один не большой компонент, для того чтобы она могла работать Redis.
1 | python3 -m pip install channels_redis |
В Redis будет временно сохранятся наши сообщения, для этого она и нужна.
Примечание:
Redis – БД типа NoSQL, которая хранит данные в ОЗУ, доступ к которым осуществляется по ключу если хотите узнать подробнее, то зайдите по ссылки.
Теперь не много изменим файл settings.py, добавим не большой список.
1 2 3 4 5 6 7 8 | CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [('127.0.0.1', 6379)], }, }, } |
Тут мы настроили работу с Redis, остальные настройки в дрогой статье, конкретно про библиотеку.
Создание проекта:
Теперь перейдём к созданию проекта, тут первым делом во файле «models.py», создадим модель для сообщений, примерно так:
1 2 3 4 5 6 | from django.db import models class Message(models.Model): id = models.AutoField(primary_key=True, unique=True) text = models.CharField(max_length=255) |
Тут не чего такое нет, модель имеет только идентификатор сообщения и текст, дальше нужно сделать миграции, используете эти команды:
1 2 | python3 manage.py makemigrations python3 manage.py migrate |
Дальше создадим файл «routing.py», это аналог «urls.py», только для WebSocket.
1 2 3 4 5 6 7 | from django.urls import re_path from . import consumers websocket_urlpatterns = [ re_path(r'ws/chat/', consumers.ChatConsumer), ] |
Здесь мы назначаем только один путь, где будут обрабатывается все WS запросы, следующие что нужно сделать, это создать файл «consumers.py» и в нём делаем класс ChatConsumer
, он будет обрабатывать все WS запросы.
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | # Импорт для работы с JSON import json # Импорт для асинхронного программирования from channels.generic.websocket import AsyncWebsocketConsumer # Импорт для работы с БД в асинхронном режиме from channels.db import database_sync_to_async # Импорт модели сообщений from .models import Message # Класс ChatConsumer class ChatConsumer(AsyncWebsocketConsumer): # Метод подключения к WS async def connect(self): # Назначим пользователя в комнату self.room_group_name = "1" # Добавляем новую комнату await self.channel_layer.group_add( self.room_group_name, self.channel_name ) # Принимаем подключаем await self.accept() # Метод для отключения пользователя async def disconnect(self, close_code): # Отключаем пользователя await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) # Декоратор для работы с БД в асинхронном режиме @database_sync_to_async # Функция для создания нового сообщения в БД def new_message(self, message): # Создаём сообщение в БД Message.objects.create(text=message) # Принимаем сообщение от пользователя async def receive(self, text_data=None, bytes_data=None): # Форматируем сообщение из JSON text_data_json = json.loads(text_data) # Получаем текст сообщения message = text_data_json['message'] # Добавляем сообщение в БД await self.new_message(message=message) # Отправляем сообщение await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': message, } ) # Метод для отправки сообщения клиентам async def chat_message(self, event): # Получаем сообщение от receive message = event['message'] # Отправляем сообщение клиентам await self.send(text_data=json.dumps({ 'message': message, }, ensure_ascii=False)) |
Теперь разберём файл, в начале мы подключаем все нужные компоненты, их особо не буду объяснять, так как в комментариях всё понятно написано.
Внутри класса первым делом идёт метод который отслеживает подключения пользователя в комнату, то есть, если он будет писать туда сообщения, то его получат все кто находится в этой комнате, можете заметить, что я просто назначаю номер комнаты один, это сделано для того, чтобы все сидели в одном чате, а так вы можете в URL передавать номер комнаты и назначать пользователя туда, когда он подключается.
Потом пишем метод disconnect()
, он срабатывает когда клиент отключается от WebSocket, создаём функцию с декоратором @database_sync_to_async
, он позволяет работать с БД асинхронная, это нужно, потому что Django по умолчанию работает синхронна, если этого не сделать, то будет ошибка, создаём метод для сохранения сообщения в БД.
Дальше пишем метод для принятии сообщений от клиента, и так как мы получаем JSON массив, мы превращаем его в обычный Python список, получаем сообщение, используем метод new_message()
и отправляем данные методу для отправки клиентам сообщений, в методе chat_message()
, отправляем сообщение всем подключённым клиентам.
На этом код для WebSockrt на сервере закончился, теперь создадим JavaScript скрипт для работы с этим.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | let chat = document.querySelector("#chat") let input = document.querySelector("#message-input") let btnSubmit = document.querySelector("#btn-submit") const webSocket = new WebSocket('ws://' + window.location.host + '/ws/chat/'); webSocket.onmessage = function(e) { const data = JSON.parse(e.data); chat.innerHTML += '<div class="msg">' + data.message + '</div>' }; btnSubmit.addEventListener("click", () => { message = input.value; webSocket.send(JSON.stringify({ 'message': message })); input.value = ''; }) |
Этот скрипт очень простой и короткий, поэтому я его не буду объяснять, да и в целом это статья про Python django, вы уже должны хорошо знать JS.
Теперь надо создать HTML шаблон, сделаем это в папке «templates», в главном приложение, где вся логика, назовём файл «room.html».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Chat Room</title> {% load static %} </head> <body> <input id="message-input" type="text" size="100"><br> <input id="btn-submit" type="button" value="Send"> <div id="chat"> </div> <script type="text/javascript" src="{% static 'script.js' %}"></script> </body> </html> |
Добавим рендаринг этой страницы и прописать URL до неё.
1 2 3 4 5 | from django.shortcuts import render def chat(request): return render(request, 'room.html') |
Добавляем URL:
1 2 3 4 5 6 7 8 9 | from django.contrib import admin from django.urls import path from main import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.chat) ] |
На этом всё закончилось, всё должно работать отлично.
Вывод:
В этой статье вы прочитали как сделать чат на Python Django с использованием библиотеки channels для WebSocket, если вас она заинтересовала, то почитайте официальную документацию.