Django校园聊天系统开发实战:WebSocket实时通信详解

发布时间:2026/8/31 17:23:54
Django校园聊天系统开发实战:WebSocket实时通信详解 简介这是一套基于Django框架开发的校园Chat在线聊天系统源码面向Python初学者及毕业设计、课程设计学习者解决校园场景下轻量级即时通讯与主题化互动需求。系统采用Python 3.8DjangoMySQL 5.7技术栈支持管理员审核机制、多主题场景交友/学习/生活服务管控、问答统计及好友式在线文字聊天兼顾功能完整性与工程可实践性。压缩包共393个文件含46个核心Python后端逻辑文件、11个HTML前端页面、44个JS交互脚本、25个CSS样式文件、41个PNG与8个JPG资源图以及SQL数据库脚本和LW文档整体大小为187.27MB。已有79人下载学习资源结构清晰包含可直接运行的完整项目骨架、数据库初始化脚本、主题场景配置模块及用户权限分离实现特别适合用于毕设快速原型搭建或Web全栈入门实战训练。1. 项目背景与需求拆解1.1 为什么做校园聊天系统看到5p050校园chat在线聊天系统(django).zip这个项目名第一反应是这大概率是一个课程设计或者毕业设计的产物也可能是某个社团、实验室内部想要搭一套自己的即时通讯工具。5p050这个编号通常是学校教务系统或者选题系统里的题目编号说明这是一道典型的Web开发综合练习题。校园聊天系统这个选题在高校里非常常见原因很直接它几乎覆盖了Web开发的核心知识点。从用户注册登录、好友关系管理、在线状态维护到消息的实时收发每一步都在考察你对手写CRUD之外的真正理解。相比图书管理系统、学生信息管理系统这类纯增删改查项目聊天系统多了一层实时性的挑战而这恰恰是区分普通作业和高质量项目的重要分水岭。另一个现实原因是校园聊天系统的使用场景非常贴合学生群体。班级通知、课程讨论、社团协作、宿舍闲聊师生之间、同学之间天然需要这样一个轻量级的沟通工具。比起直接拉微信群自己搭建的系统在可控性、扩展性和学习价值上都强得多而且还能作为后续找工作时简历上的亮点项目。1.2 Django在这个项目里扮演什么角色Django作为Python生态里最成熟的全栈Web框架在这个项目里承担的是完整的后端逻辑。从数据模型的定义、ORM查询、表单验证到URL路由和模板渲染整个业务层的骨架都由Django来搭建。相比Flask这种微框架Django自带Admin后台、认证系统、ORM和迁移机制对校园聊天这种业务逻辑中等复杂度的项目来说开箱即用的组件能省下大量重复造轮子的时间。我见过不少人纠结要不要用Flask甚至FastAPI来做这类项目但我的看法是如果你是在校学生选Django几乎是综合性价比最高的方案。原因有三点第一Django的ORM让你不需要写一行SQL就能完成所有数据操作学习曲线友好第二Django自带Admin后台调试数据和查看用户关系的时候特别方便第三国内绝大多数高校的Web课程和毕业设计都以Django为蓝本参考资料和现成方案最多踩坑时能找到的解决方案也最全。1.3 项目的核心功能范围从标题中的chat在线聊天系统可以推断这套系统至少要包含以下几个核心模块用户认证模块注册、登录、退出登录这是所有功能的基础。需要处理密码加密存储、会话保持、登录状态校验等。好友管理模块添加好友、删除好友、好友列表展示。有些实现还会包含好友申请、同意/拒绝等流程。在线状态管理实时显示好友是否在线。这个功能在Web端实现起来有多种方案复杂度差异很大。消息收发模块一对一私聊、消息历史记录、未读消息提示。这是整个系统的核心价值所在。会话列表模块展示最近的联系人列表类似微信的聊天界面布局。有些做得更完整的版本还会加入群聊、文件传输、表情包等功能但那些属于锦上添花的部分。我建议在做第一版时先把上述五个模块做扎实再考虑扩展。2. 技术方案选型与架构设计2.1 实时通信方案轮询、长轮询还是WebSocket聊天系统的核心技术难点在于实时消息推送。Web端是一个请求-响应模型服务器不能主动向浏览器推送数据这就需要一个机制来解决对方发消息给我我要立刻知道这个问题。目前主流方案有三种轮询、长轮询和WebSocket。轮询是前端每隔几秒发一次HTTP请求问服务器有没有新消息。这种方式实现最简单但效率低下请求频繁且大部分情况下都是空响应。长轮询是前端发请求后服务器挂起这个请求直到有新消息才返回再立即发起下一次请求。这种方式比轮询实时性好一些但对服务器连接资源消耗较大。WebSocket则是建立一条TCP长连接双方可以随时互发数据真正实现了全双工通信是目前聊天系统的首选方案。Django生态里对WebSocket的支持也相当成熟了。传统方案是在Django之外单独部署一个Daphne或Uvicorn服务器来运行ASGI应用配合Channels库实现WebSocket通信。不过我看到现在很多校园项目里用的是另一条更轻的路线Django REST Framework提供普通HTTP接口来处理登录、好友、历史消息等管理类操作WebSocket只负责实时消息通道。前端通过WebSocket连接建立后服务器主动推送新消息前端也可通过WebSocket发送消息。订阅、推送分别走的通道不同逻辑更清晰。2.2 数据模型设计从用户到消息数据库表的设计直接影响整个系统的扩展性和查询效率。我建议至少设计以下这几张表用户表可以直接用Django自带的User模型扩展通过OneToOne字段关联一个Profile表来存头像、昵称、个性签名等扩展信息。不建议直接修改User表因为Django内置的认证系统对User表有很多内部假设改动容易引发不可预知的问题。好友关系表是聊天系统的关键设计点。我见过很多初学者会设计成我关注谁和谁关注我两张表但好友关系其实是双向的用一张表就行。核心字段就两个user和friend都指向User表。要判断两人是否是好友只需要查这条记录是否存在。删除好友时把这条记录删掉就行。不过注意这个模型下如果用户A把B加为好友B的列表里也会出现A这是一种简化的对称模型。如果要实现非对称的关注关系就需要额外设计。消息表的设计更讲究。基础字段包括发送者、接收者、内容、发送时间、是否已读。但如果要支持群聊就需要引入会话Conversation和会话成员ConversationMember两张表一对一的私聊本质上是一个只有两个成员的会话。我建议从一开始就按会话模型来设计哪怕第一版只做私聊这样后续扩展群聊时不需要重构数据表。2.3 前端页面布局与交互校园聊天系统的前端不需要太花哨但基础体验要做好。整体页面布局可以参照微信网页版的经典三栏结构左侧是用户信息区中间是会话列表右侧是聊天窗口。这个布局在桌面端浏览器上体验最好也是大多数聊天系统的通用方案。中间会话列表要展示最近的联系人头像、昵称、最后一条消息的预览和时间未读消息数用红色角标显示。点击某个会话后右侧聊天窗口展示完整的聊天记录最下方是输入框和发送按钮。聊天记录区域要支持滚动加载历史消息进入会话后自动滚动到最新一条。消息的展示上自己的消息靠右用蓝色或绿色背景气泡对方的消息靠左用白色或灰色气泡。这个视觉区分一定要做否则整个聊天界面会非常难用。时间戳的处理也值得一提同一天的消息显示上午10:30这种格式就好跨天的显示昨天或具体日期混在一起会很乱。3. Django环境的搭建与项目初始化3.1 开发环境准备动手写代码之前先把环境搭好。我建议使用Python 3.10以上版本Django 4.x是当前最稳定的选择。Django 5.0虽然已经发布但对一些第三方库的兼容性还需要时间检验校园项目不必追求最新版本。虚拟环境是必须的我遇到过太多因为依赖冲突导致的在我电脑上能跑问题。用venv创建虚拟环境python -m venv venv source venv/bin/activate # Windows下执行 venv\Scripts\activate激活后在虚拟环境里安装依赖pip install django channels channels-redis daphnechannels是Django的WebSocket扩展channels-redis用于在Redis里存储频道层的消息。如果没有装Redis也可以在开发阶段使用InMemory通道层但生产环境必须用Redis。创建项目和应用时我习惯拆分成多个app按业务模块划分而不是把所有代码堆在一个app里。聊天系统至少应该拆成users、friends、chat三个app分别负责用户管理、好友关系和聊天功能。这样每个app的职责清晰后续维护和扩展都方便。django-admin startproject campus_chat cd campus_chat python manage.py startapp users python manage.py startapp friends python manage.py startapp chat3.2 Django项目基础配置创建完项目后首先要修改settings.py。需要重点关注这几项配置。INSTALLED_APPS里要加入channels和我们新建的三个app。加入channels之后还要设定ASGI应用入口INSTALLED_APPS [ daphne, django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, channels, users, friends, chat, ] ASGI_APPLICATION campus_chat.asgi.application注意daphne必须放在django.contrib.admin之前否则runserver会报错。CHANNEL_LAYERS配置如果是开发环境可以用内存通道层顶一下CHANNEL_LAYERS { default: { BACKEND: channels.layers.InMemoryChannelLayer } }但开发完之后上线一定要切换到Redis。在settings.py里配置Redis连接信息用channels_redis这个包作为后端。Redis的安装和启动这里就不展开了Windows下有安装包Linux下用apt或yum装一下就行。数据库配置方面开发阶段直接用SQLite就行零配置开箱即用。但要注意Django默认的SQLite配置在并发访问较多时可能会有锁冲突后期如果部署到真实的校园服务器上建议换成PostgreSQL或者MySQL配置方法在Django官方文档里有详细的示例。3.3 用户模型的扩展与认证集成Django内置的User模型已经包含了用户名、密码、邮箱、姓名等基础字段但聊天系统还需要昵称、头像、个性签名这些扩展信息。我采用的方式是创建一个Profile模型通过OneToOneField和User关联from django.db import models from django.contrib.auth.models import User from django.db.models.signals import post_save from django.dispatch import receiver class Profile(models.Model): user models.OneToOneField(User, on_deletemodels.CASCADE, related_nameprofile) nickname models.CharField(max_length50, blankTrue) avatar models.ImageField(upload_toavatars/, blankTrue, nullTrue) signature models.CharField(max_length200, blankTrue) created_at models.DateTimeField(auto_now_addTrue) def __str__(self): return self.nickname or self.user.username receiver(post_save, senderUser) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(userinstance) receiver(post_save, senderUser) def save_user_profile(sender, instance, **kwargs): instance.profile.save()用signal的方式创建Profile这样在注册用户时就不用手动去创建关联的Profile对象省一步操作也不容易漏。注册接口可以用Django的UserCreationForm来快速实现但为了返回JSON数据给前端我一般用DRF的Serializer来写注册接口。密码存储由Django的认证系统自动处理使用PBKDF2算法加盐加密这一点非常安全不需要自己再造轮子。登录接口用DRF的TokenAuthentication或者JWT都可以。校园项目里JWT更主流一些因为它在移动端和Web端都能很好地工作无状态也好扩展。不过如果只是做课程设计Django自带的Session认证加上CSRF保护也完全够用还少装一个依赖。4. 核心功能模块的代码实现4.1 好友管理模块的具体实现好友功能的实现思路其实很清晰。用一张表记录好友关系然后提供添加、删除、查询三个接口。如果要做好友申请流程还需要加一张好友申请表。我这里给出一个包含申请流程的完整设计。FriendRequest表记录申请记录字段包括发起者、接收者、状态pending/approved/rejected、创建时间。当用户A向B发送好友申请时插入一条状态为pending的记录。用户B同意后把状态改为approved同时在好友关系表里创建两条记录A-B和B-A。如果是拒绝把状态改为rejected即可。Friend表就两个字段user和friend。查询某人的好友列表def get_friend_list(user): friendships Friend.objects.filter(useruser) friends [friendship.friend for friendship in friendships] return friends这里有个效率问题查询好友列表时每个friend都会触发一次User表的查询。如果用户有几百个好友会产生N1次查询。优化方式是用select_related或prefetch_relatedfriendships Friend.objects.filter(useruser).select_related(friend)一次查询就把friend的所有关联数据拉回来性能好很多。这个细节在聊天系统里特别重要因为会话列表页面每次渲染都需要查好友信息查询效率直接决定了页面的响应速度。4.2 消息发送与历史记录消息表的模型设计我建议采用会话模型。先定义Conversation和Messageclass Conversation(models.Model): name models.CharField(max_length100, blankTrue) # 群聊名称私聊可空 is_group models.BooleanField(defaultFalse) created_at models.DateTimeField(auto_now_addTrue) members models.ManyToManyField(User, related_nameconversations) last_message models.ForeignKey(Message, nullTrue, blankTrue, on_deletemodels.SET_NULL, related_name) class Message(models.Model): conversation models.ForeignKey(Conversation, on_deletemodels.CASCADE, related_namemessages) sender models.ForeignKey(User, on_deletemodels.CASCADE, related_namesent_messages) content models.TextField() created_at models.DateTimeField(auto_now_addTrue) is_read models.BooleanField(defaultFalse)私聊的场景下创建会话前先检查这两个用户是否已经有会话了。这样避免两个用户之间出现多个重复会话。实现方式是查conversation表找到同时包含这两个成员且is_group为False的会话。发送消息的接口逻辑比较简单拿到会话ID和消息内容创建Message记录然后更新会话的last_message字段最后通过WebSocket推送给对方。这里要特别注意事务问题。如果是用WebSocket直接发送消息的落库和推送这两个操作要保证原子性不能出现消息入库了但推送失败的情况。我的做法是先把消息写入数据库再通过channel layer推送。如果推送失败接收方下次上线时可以通过拉取未读消息的方式把消息拿到不会丢消息。4.3 Channels实现WebSocket实时通信Channels是用Django实现WebSocket的标准方案它的核心是channel layer和consumer。consumer是一个类用来处理WebSocket连接、接收和发送消息。在chat app下创建consumers.pyimport json from channels.generic.websocket import AsyncWebsocketConsumer from channels.db import database_sync_to_async class ChatConsumer(AsyncWebsocketConsumer): async def connect(self): self.user self.scope[user] if self.user.is_anonymous: await self.close() else: # 每个用户加入一个以自己ID命名的group self.group_name fuser_{self.user.id} await self.channel_layer.group_add( self.group_name, self.channel_name ) await self.accept() # 标记用户在线 await self.set_online_status(True) async def disconnect(self, close_code): await self.channel_layer.group_discard( self.group_name, self.channel_name ) await self.set_online_status(False) async def receive(self, text_data): data json.loads(text_data) message data[message] to_user_id data[to] # 保存消息到数据库 await self.save_message(to_user_id, message) # 推送给接收者 await self.channel_layer.group_send( fuser_{to_user_id}, { type: chat_message, message: message, from: self.user.username, timestamp: str(timezone.now()), } ) async def chat_message(self, event): await self.send(text_datajson.dumps({ message: event[message], from: event[from], timestamp: event[timestamp], }))connect方法里判断用户是否已认证的关键是self.scope[user]这需要配置AuthMiddlewareStack才能获取到。在asgi.py里配置from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application import chat.routing application ProtocolTypeRouter({ http: get_asgi_application(), websocket: AuthMiddlewareStack( URLRouter(chat.routing.websocket_urlpatterns) ), })这个方案在开发环境跑起来没问题但需要注意一点AuthMiddlewareStack依赖Session而Django的Session默认存储在数据库里。每次WebSocket连接时都要查一次数据库获取Session高并发下性能会有点紧张。生产环境可以换成Redis存储Session把SESSION_ENGINE配置为redis能缓解这个问题。4.4 未读消息与在线状态未读消息的实现有两种主流思路。一种是维护一个单独的未读消息表每次发送消息时插入一条记录接收方阅读后删除。另一种是直接在Message表上做状态标记查询时统计未读数量。两种方案各有优劣。单独的表查询速度快但维护两处数据的一致性比较麻烦状态标记方案简单直观但message表数据量大的时候统计未读数量会慢。对于校园项目这个量级我推荐直接在Message表上做标记每次查询时用SQL的COUNT函数统计未读数量配合数据库索引性能完全够用。在线状态的实现则要看用什么通信方案。如果用WebSocket用户建立连接时设一个Redis标记key值为user.idvalue为online断开连接时删除标记。前端在会话列表里渲染在线状态时先批量获取好友ID列表再一次性查Redis判断每个用户是否在线最后合并结果返回给前端。Redis持久化配置要改一下不然服务重启后在线状态就全丢了。5. 前端页面与交互实现5.1 页面整体结构与样式前端部分我建议用原生HTML/CSS/JavaScript加一点轻量级的处理就够了不必上React或Vue。校园项目最重要的是快速完成、功能完整引入大型前端框架会明显拉长开发周期。HTML结构可以这样规划div idapp div idsidebar div iduser-info当前用户信息/div div idconversation-list会话列表/div /div div idchat-panel div idchat-header对方信息/div div idchat-messages消息区域/div div idchat-input输入区域/div /div /divCSS方面整体用flex布局让页面撑满全屏。侧边栏宽度固定为280px左右聊天区域占剩余空间。背景色建议用浅灰或白色聊天区域内自己的消息气泡用蓝色背景白色文字对方的用浅灰背景黑色文字。未读消息角标用红色圆形数字居中。5.2 消息发送与接收的完整流程页面上用户输入消息后点击发送按钮前端要做的事情有三件一是将消息内容通过WebSocket推送到后端二是将消息以气泡形式插入到聊天区域内三是清空输入框。function sendMessage() { const input document.getElementById(message-input); const content input.value.trim(); if (!content) return; const payload { message: content, to: currentFriendId }; websocket.send(JSON.stringify(payload)); displayMessage({ content: content, isSelf: true }); input.value ; }接收消息时WebSocket的onmessage回调触发解析JSON数据后把消息气泡渲染到聊天区域底部。这里要注意一个用户体验的细节如果当前正在和对方聊天收到消息后要立即滚动到底部如果当前并没有打开对方的聊天窗口则需要在会话列表里更新最后一条消息的预览并让未读角标加1。5.3 会话列表的刷新策略很多初学Django聊天系统的同学会在这个问题上犯难会话列表里的最后一条消息、未读数量、在线状态这些信息什么时候更新最简单粗暴的方式是定时轮询每隔3到5秒用AJAX请求一次后端接口重新拉取会话列表数据。这种方式实现简单、代码量少但有一个明显的体验问题如果用户就在当前聊天窗口里会话列表没变化时频繁刷新会闪烁。更优雅的方案是结合WebSocket推送来驱动会话列表更新。后端收到新消息推送到接收方时不只发送消息本身同时发送一个会话更新的事件让前端刷新会话列表。这样会话列表只在真正有变化时才更新实时性和性能都能兼顾。不过考虑到开发的工作量我建议第一版采用定时轮询加WebSocket推送混合的方式聊天窗口内消息实时性靠WebSocket会话列表的未读数量、最后一条消息预览靠每5秒的定时刷新。这样即使在WebSocket连接断开的场景下也能保证会话列表最终一致不会出现漏消息的严重Bug。6. 常见问题与解决方案6.1 WebSocket连接失败或频繁断开这个问题是Django聊天系统开发中最常见也最让人头疼的问题。现象通常有两种一是浏览器控制台出现WebSocket连接失败二是连接一两分钟后自动断开。连接失败首先要检查Daphne服务器是否正常启动。Django自带的runserver命令默认不走ASGI必须用daphne来启动daphne -b 0.0.0.0 -p 8000 campus_chat.asgi:application检查asgi.py里是否正确配置了ProtocolTypeRouter以及URLRouter中的路径是否与前端连接的地址一致。连接断开则多半是超时或心跳配置的锅。WebSocket默认在一段时间内没有数据交互代理服务器或浏览器会主动断开连接。解决方案是前端定时发送ping消息后端收到后回复pong保持连接活跃。我在实际项目中用的是每30秒发一次心跳实测下来稳定很多。6.2 CSRF验证导致的POST请求失败用Django的Session认证时所有的POST请求都需要携带CSRF token。我遇到过很多次前端发送AJAX请求时报403错误排查了半天发现是CSRF token没带上。解决方案有两种如果前端是用Django的模板渲染的页面可以在模板里使用{% csrf_token %}获取token然后在AJAX请求里设置请求头。如果是前后端分离的模式推荐使用JWT认证替换Session认证彻底绕开CSRF问题。6.3 消息丢失与重复推送消息丢失的典型场景是用户A发给用户B消息时B的WebSocket连接刚好断开消息推送到channel layer时找不到对应的channelB就收不到了。解决思路是消息在推送失败时自动落库为未读消息B下次上线或打开聊天窗口时通过拉取未读消息接口把消息取回来。消息重复推送的场景则通常是因为WebSocket重连后没有重新初始化聊天页面或者前端的onmessage回调重复注册了。解决方法是重连成功后先清空原有的事件监听再重新注册。我的经验是每次WebSocket的onmessage绑定前先赋值为null避免重复叠加。6.4 数据库锁冲突与并发写入校园聊天系统虽然并发量不会特别大但如果用SQLite当数据库多个用户同时发消息时偶尔会报数据库锁错误的异常。SQLite在写操作时会锁定整个数据库文件导致其他写请求排队等待频率高了就会超时报错。最简单的规避方式是把数据库换成PostgreSQL或MySQL。如果一定要用SQLite可以调整Django的数据库配置开启WAL模式DATABASES { default: { ENGINE: django.db.backends.sqlite3, NAME: BASE_DIR / db.sqlite3, OPTIONS: { timeout: 20, }, } }这个timeout参数设置的是获取数据库锁的等待时间默认是5秒改成20秒能缓解大部分锁冲突问题。但说实话这只是权宜之计真要上线还是换数据库稳妥。6.5 Django版本兼容性问题不同Django版本之间的差异非常大尤其是Channels和Daphne的版本搭配。我见过有同学装了Django 5.0配了最新版Channels结果在asgi.py里跑不起来。我的建议是如果跟着网上的教程走先确认教程用的Django版本然后严格按那个版本安装依赖。不要用最新版赌兼容性除非你有充足的时间去排查不兼容的问题。目前比较稳妥的组合是Django 4.2 Channels 4.0 Daphne 4.0。这三个版本之间的兼容性已经经过大量项目的验证网上资料也最多。7. 项目部署与后续扩展7.1 在校园服务器上的部署方案部署Django聊天系统到校园服务器需要考虑的事情比本地开发多很多。首先是运行方式开发时用的Daphne单进程只能用于测试生产环境应该用Supervisor或systemd来守护Daphne进程确保进程崩溃后能自动重启。Nginx作为反向代理部署在最前面负责处理静态文件、转发HTTP请求和WebSocket请求。配置Nginx时要特别留意WebSocket的升级头location /ws/ { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; }忘记配置Upgrade和Connection请求头是WebSocket部署最常见的坑少了这两行浏览器会一直报连接错误。静态文件的处理也要注意。Django在DEBUGFalse模式下不会自动提供静态文件服务需要执行python manage.py collectstatic把所有静态文件收集到一个目录里然后让Nginx直接访问这个目录。7.2 从一对一私聊扩展到群聊如果你做完私聊功能后觉得不过瘾想把这个项目升级成带群聊的完整系统我建议你在数据模型上提前做好准备。前面提到的Conversation表中已经有is_group字段群聊只是在这个基础上增加群名称、群头像、群公告等字段以及创建群、加入群、退出群的接口。群聊的消息推送逻辑和私聊类似区别在于推送到群聊时要遍历群成员往每个成员的channel group发送消息。这个操作在channel layer里可以用group_send一次性实现前提是每个成员都已经加入了以自己ID命名的group。群聊的消息已读逻辑比私聊复杂一些需要维护每个成员的最后阅读位置可以给ConversationMember增加一个last_read_message字段来记录。不过这块属于扩展功能课程设计阶段不做也完全合理但保留这个字段在数据表里以后扩展时会省很多事。7.3 项目后续还能怎么扩展做完基础的聊天功能后这个项目可以轻松扩展出不少加分项。发送图片和文件可以直接在Message表里增加一个attachment字段记录文件路径前端用文件上传组件配合AJAX就能实现。消息撤回功能需要记录消息状态字段撤回后把内容替换为消息已撤回。历史消息搜索可以通过Django的ORM实现简单的关键字过滤配合全文索引还能做得更专业。如果想把项目做得更有亮点可以在系统里接入一个简单的表情包系统或者加上深色模式切换。这些功能本身难度不大但能让你的项目演示和答辩时的观感提升不少。我个人在实际操作中的体会是整个校园chat项目开发工作量最大的反而不是实时通信本身而是好友管理、会话列表、未读消息这些基础功能的打磨。做的时候不要急着直接上WebSocket先把用户认证、好友关系、历史消息这些走通再在这个基础上加实时推送整个开发过程会顺畅很多。另外最后部署前一定要把Django的DEBUG关掉SECRET_KEY换成环境变量不要用代码里写死的默认值这些安全细节在答辩时老师都很爱问。本文还有配套的精品资源点击获取