使用 Django Channels 构建实时聊天应用(包含用户认证和消息持久化)

文章目录

Django Channels 是 Django 的一个扩展,允许在 Web 应用中添加实时功能,例如 Websockets、HTTP2 和其他协议。本文将介绍如何使用 Django Channels 构建一个简单的实时聊天应用程序。

准备工作

首先,确保你已经安装了 Django 和 Channels。你可以使用以下命令安装:

bash 复制代码
pip install django channels

创建 Django 项目

使用以下命令创建一个新的 Django 项目:

bash 复制代码
django-admin startproject realtime_chat

然后进入项目目录:

bash 复制代码
cd realtime_chat

创建应用程序

创建一个新的 Django 应用程序:

bash 复制代码
python manage.py startapp chat

配置项目

settings.py 文件中添加 Channels 的配置:

python 复制代码
# settings.py

INSTALLED_APPS = [
    ...
    'channels',
    'chat',
]

ASGI_APPLICATION = 'realtime_chat.routing.application'

创建一个新的 ASGI 路由文件 routing.py

python 复制代码
# routing.py

from channels.routing import ProtocolTypeRouter

application = ProtocolTypeRouter({

})

编写 Consumer

consumers.py 文件中编写一个简单的 Consumer:

python 复制代码
# chat/consumers.py

from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        pass

编写路由

routing.py 文件中添加路由配置:

python 复制代码
# routing.py

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.urls import path
from chat.consumers import ChatConsumer

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter([
            path('chat/', ChatConsumer.as_asgi()),
        ])
    ),
})

创建 URL 路由

urls.py 文件中添加 URL 路由:

python 复制代码
# chat/urls.py

from django.urls import path
from . import consumers

websocket_urlpatterns = [
    path('chat/', consumers.ChatConsumer.as_asgi()),
]

在主项目的 urls.py 中包含 Chat 应用的路由:

python 复制代码
# realtime_chat/urls.py

from django.urls import path, include

urlpatterns = [
    ...
    path('chat/', include('chat.urls')),
]

运行应用

运行 Django 服务器:

bash 复制代码
python manage.py runserver

现在,你可以通过访问 http://localhost:8000/chat/ 来测试你的实时聊天应用了。

用户认证

首先,我们将使用 Django 自带的认证系统来处理用户认证。在 settings.py 中启用认证系统:

python 复制代码
# settings.py

INSTALLED_APPS = [
    ...
    'django.contrib.auth',
    'django.contrib.contenttypes',
    ...
]

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
]

然后,我们需要修改 ChatConsumer,以便处理用户认证:

python 复制代码
# chat/consumers.py

from channels.generic.websocket import AsyncWebsocketConsumer
from django.contrib.auth.models import AnonymousUser

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope["user"]
        if isinstance(self.user, AnonymousUser):
            await self.close()
        else:
            await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        pass

现在,只有经过身份验证的用户才能连接到聊天消费者。

消息持久化

我们希望用户在重新加载页面后能够看到之前的聊天消息。为了实现这一点,我们将使用 Django 的数据库来存储消息。

首先,我们需要创建一个模型来存储聊天消息:

python 复制代码
# chat/models.py

from django.db import models
from django.contrib.auth.models import User

class Message(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user.username}: {self.content}"

然后,我们需要修改 ChatConsumer,以便在接收到消息时将其保存到数据库中:

python 复制代码
# chat/consumers.py

from channels.generic.websocket import AsyncWebsocketConsumer
from django.contrib.auth.models import AnonymousUser
from .models import Message
import json

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope["user"]
        if isinstance(self.user, AnonymousUser):
            await self.close()
        else:
            await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        content = text_data_json['message']

        message = Message.objects.create(user=self.user, content=content)
        message.save()

现在,当用户发送消息时,它们将被保存到数据库中。

显示历史消息

最后,我们需要修改前端以显示历史消息。在 ChatConsumer 中,我们可以添加一个方法来发送历史消息给客户端:

python 复制代码
# chat/consumers.py

class ChatConsumer(AsyncWebsocketConsumer):
    ...

    async def fetch_messages(self):
        messages = Message.objects.all()[:10]  # 获取最近的10条消息
        content = {
            'command': 'messages',
            'messages': self.messages_to_json(messages)
        }
        await self.send(text_data=json.dumps(content))

    @staticmethod
    def messages_to_json(messages):
        result = []
        for message in messages:
            result.append({
                'user': message.user.username,
                'content': message.content,
                'timestamp': str(message.timestamp)
            })
        return result

然后,在连接建立时调用这个方法:

python 复制代码
# chat/consumers.py

async def connect(self):
    ...
    await self.fetch_messages()

在前端,你可以使用 JavaScript 来接收并显示历史消息。

结论

通过添加用户认证和消息持久化功能,我们的实时聊天应用变得更加完善和实用。你可以根据需要进一步定制和扩展这个应用,例如添加在线用户列表、私聊功能等。Django Channels 提供了强大的工具,让你可以构建出功能丰富的实时 Web 应用。

相关推荐
Ticnix20 分钟前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人23 分钟前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl27 分钟前
OpenClaw 深度技术解析
前端
崔庆才丨静觅30 分钟前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人39 分钟前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼42 分钟前
shadcn/ui,给你一个真正可控的UI组件库
前端
布列瑟农的星空1 小时前
前端都能看懂的Rust入门教程(三)——控制流语句
前端·后端·rust
Mr Xu_1 小时前
Vue 3 中计算属性的最佳实践:提升可读性、可维护性与性能
前端·javascript
jerrywus1 小时前
我写了个 Claude Code Skill,再也不用手动切图传 COS 了
前端·agent·claude
玖月晴空1 小时前
探索关于Spec 和Skills 的一些实战运用-Kiro篇
前端·aigc·代码规范