实战 | 使用 Python 开发一个在线聊天室
回复“书籍”即可获赠Python从入门到进阶共10本电子书
上篇使用 Django 传统的 MTV 模式进行开发,实现一个在线聊天室的功能。
中篇在上篇基础上加入数据存储,实现聊天记录的保存。
下篇则采用后端 Django + 前端 Vue 对传统的 Web 模开发式进行改造。
创建虚拟环境
python -m venv django3_env
安装依赖库
pip install django
Channels 封装了 Django 的原生异步视图支持,让 Django 项目不仅可以处理 HTTP,还可以处理需要长时间连接的协议,比如:WebSockets、MQTT、聊天机器人、业余无线电等等。
pip install channels
pip install channels_redis
创建项目
django-admin startproject chat_backend
python manage.py startapp chat
配置项目
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels',
'chat',
]
templates
的文件夹,然后定义 HTML 模板路径:TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BASE_DIR / 'templates'
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
ASGI_APPLICATION = "chat_backend.asgi.application"
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
创建视图
# 首页
def index(request):
return render(request,'index.html',locals())
# 聊天室
def room(request,room_name):
room_name = room_name
username = request.GET.get('username', '游客')
return render(request,'room.html',locals())
index()
返回 index.html,视图函数room()
返回 room.html,这两个 HTML 文件需要我们在templates
文件夹中进行创建。定义路由
urls.py
的文件,在其中写入如下内容:from django.urls import path
from chat.views import *
# HTTP URL
urlpatterns = [
path('',index,name="index"),
path('<str:room_name>/',room,name="room")
]
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('chat.urls')),
]
编写 WebSocket 后端
consumers.py
的文件(意为消费者,是 Channels 中的一个重要概念),在其中,我们引入 WebSocket 类:
from channels.generic.websocket import AsyncWebsocketConsumer
ChatConsumer
的类,并在其中重写 WebSocket 的连接、关闭连接、消息接收等方法,代码如下所示:class ChatConsumer(AsyncWebsocketConsumer):
# 连接
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# 加入聊天室
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
)
#
async def receive(self, text_data=None, bytes_data=None):
data = json.loads(text_data)
message = data['message']
username = data['username']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message,
'username': username
}
)
# 接收消息
async def chat_message(self, event):
message = event['message']
username = event['username']
# 发送消息到 Websocket
await self.send(text_data=json.dumps({
'message': message,
'username': username
}))
import os
from django.core.asgi import get_asgi_application
from django.urls import path
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from chat.consumers import ChatConsumer
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chat_backend.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter([
path("ws/<str:room_name>/",ChatConsumer.as_asgi()),
])
)
})
前端连接 WebSocket
WebSocket
对象,来创建 WebSocket连接:// 建立一个 websocket 连接
const chatSocket = new WebSocket(
'ws://' + window.location.host + '/ws/' + roomName + '/'
);
// websocket连接关闭后的回调函数
chatSocket.onclose = function(e) {
console.error('The socket closed unexpectedly');
};
// websocket连接从服务器收到消息的回调函数
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
if (data.message) {
if(data.username == userName){
document.querySelector('#chat-record').innerHTML += ('<div class="right_msg">' + data.username + '<div class="right-record"><span>' + data.message + '</span></div></div><br>');
}else{
document.querySelector('#chat-record').innerHTML += ('<div class="left_msg">' + data.username + '<div class="left-record"><span>' + data.message + '</span></div></div><br>');
}
} else {
alert('消息为空!')
}
};
最后
聊天记录不会保存,刷新页面之后聊天记录就会消失。
没有用户认证和鉴权,谁都能输入房间号和用户名进入聊天室。
小伙伴们,快快用实践一下吧!如果在学习过程中,有遇到任何问题,欢迎加我好友,我拉你进Python学习交流群共同探讨学习。
------------------- End -------------------
往期精彩文章推荐:
欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持
想加入Python学习群请在后台回复【入群】
万水千山总是情,点个【在看】行不行
/今日留言主题/
随便说一两句吧~~