前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实战 | 使用 Python 开发一个在线聊天室

实战 | 使用 Python 开发一个在线聊天室

作者头像
州的先生
发布2021-09-08 16:20:26
3.3K1
发布2021-09-08 16:20:26
举报
文章被收录于专栏:州的先生州的先生

在线聊天室在如今的互联网是一个很常见的产品,在各类电商的网页客服中,我们都可以接触到在线聊天。还有一个培训机构,你一打开他的网页,立马就弹出一个在线聊天框,防不胜防。

今天州的先生给大家带了一个后端 Python + 前端 Vue 的小项目教程。

这个教程分为上中下三篇,其中:

  • 上篇使用 Django 传统的 MTV 模式进行开发,实现一个在线聊天室的功能。
  • 中篇在上篇基础上加入数据存储,实现聊天记录的保存。
  • 下篇则采用后端 Django + 前端 Vue 对传统的 Web 模开发式进行改造。

非常适合学了 Django 之后写项目无从下手的朋友们。

本篇为上篇,我们将使用 Django 的传统开发模式借助视图和模板完成一个在线聊天室应用的开发。

最终效果如下所示:

直接开干吧!

创建虚拟环境

为了不与计算机上现有的 Python 模块冲突,我们新起一个 Python 虚拟环境:

代码语言:javascript
复制
python -m venv django3_env
 

进入虚拟环境,然后激活它。

安装依赖库

后端我们使用的是 Django3 框架(在本文编写时,Django 的最新版本为 3.2,所以我们不需要指定它的版本):

代码语言:javascript
复制
pip install django
 

还有一个重要的依赖库——Channels。

Channels 封装了 Django 的原生异步视图支持,让 Django 项目不仅可以处理 HTTP,还可以处理需要长时间连接的协议,比如:WebSockets、MQTT、聊天机器人、业余无线电等等。

简而言之,就是为 Django 提供了异步和非 HTTP 处理的能力

代码语言:javascript
复制
pip install channels
 

因为 Channels 中的一个功能需要使用到 Redis 作为数据通道和缓存,所以我们得安装 Redis 以及其 Python 相关的包。

而 Redis 在 Windows 上没有官方的支持,所以在这里,州的先生使用一个 Redis 的替代品 Memurai 来当 Redis 使用:

安装完成后即会作为 Windows 的服务在后台启动。

然后安装 Channels 的 Redis 配套库:

代码语言:javascript
复制
pip install channels_redis
 

创建项目

安装好所有的依赖项之后,我们开始创建 Django 项目:

代码语言:javascript
复制
django-admin startproject chat_backend
 

然后进入 chat_backend 目录,创建一个应用:

代码语言:javascript
复制
python manage.py startapp chat
 

配置项目

接着我们进行必要的配置,下述操作在 settings.py 文件中进行。

添加 channels、chat 应用到 Django 项目的应用列表:

代码语言:javascript
复制
INSTALLED_APPS = [
 
 'django.contrib.admin',
 
 'django.contrib.auth',
 
 'django.contrib.contenttypes',
 
 'django.contrib.sessions',
 
 'django.contrib.messages',
 
 'django.contrib.staticfiles',
 
 'channels',
 
 'chat',
 
]
 

在项目根目录下新建名为templates的文件夹,然后定义 HTML 模板路径:

代码语言:javascript
复制
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 应用:

代码语言:javascript
复制
ASGI_APPLICATION = "chat_backend.asgi.application"
 

最后,指定 Channels 使用的数据通道后端,在这里我们使用的是 Redis:

代码语言:javascript
复制
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

其中主机地址和端口号填写 Redis 启动后显示的默认值。

创建视图

在这个「在线聊天室」里面,一共有两个页面。一个是首页,用于输入房间号和用户名;另一个则是聊天房间的页面,用于进行聊天。

我们在 chat 应用的 views.py 下新建两个视图函数:

代码语言:javascript
复制
# 首页
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文件夹中进行创建。

定义路由

视图函数创建好之后,我们为其绑定路由,在 chat 应用下新建一个名为urls.py的文件,在其中写入如下内容:

代码语言:javascript
复制
from django.urls import path
from chat.views import *
# HTTP URL
urlpatterns = [
    path('',index,name="index"),
    path('<str:room_name>/',room,name="room")
]

然后在 chat_backend 文件夹下的 urls.py 文件内引入 chat 应用的 url 配置:

代码语言:javascript
复制
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('chat.urls')),
]

至此,「在线聊天室」这个项目的 HTTP 部分已经完成了开发。

访问首页,会显示如下图所示的页面:

我们可以输入房间号和用户名进入房间,进入房间后的页面如下图所示:

但是现在我们还不能进行在线聊天,因为在线聊天最核心的部分——WebSocket后端,我们还没有编写。

编写 WebSocket 后端

WebSocket 是一个长连接的双向通信协议。通过 WebSocket 我们可以在客户端和服务器端之间建立实时的通信,而不是像 HTTP 那样,只有客户端发起,服务器端才会响应。

在这里,我们借助 Channels 在 Django 中实现 WebSocket。

首先,在 chat 应用下新建一个名为consumers.py的文件(意为消费者,是 Channels 中的一个重要概念),在其中,我们引入 WebSocket 类:

代码语言:javascript
复制
from channels.generic.websocket import AsyncWebsocketConsumer
 

然后继承这个类,新建一个名为ChatConsumer的类,并在其中重写 WebSocket 的连接、关闭连接、消息接收等方法,代码如下所示:

代码语言:javascript
复制
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
        }))

最后,我们在 asgi 中重新声明路由。打开 chat_backend 目录下的 asgi.py 文件,将内容修改为如下所示:

代码语言:javascript
复制
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()),
      ])
  )
})

如上代码所示,HTTP 通过 get_asgi_application 以传统的 HTTP 路由进行处理,而 WebSocket 则通过 Channels 的 URLRouter 进行处理。这样我们的项目启动之后就可以同时支持 HTTP 访问和 WebSocket 访问。

前端连接 WebSocket

后端提供了 WebSocket 服务,前端需要进行连接和处理才行。

来看看前端的处理过程。

首先,通过 new 一个 WebSocket对象,来创建 WebSocket连接:

代码语言:javascript
复制
        // 建立一个 websocket 连接
        const chatSocket = new WebSocket(
          'ws://' + window.location.host + '/ws/' + roomName + '/'
        );

然后编写 WebSocket 各类事件的回调函数:

代码语言:javascript
复制
        // 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('消息为空!')
          }
        };

这样前端就完成了对后端 WebSocket 的连接和消息接收。

最后

运行项目,我们就可以在网页上进行实时在线聊天了。

当然,现在这个项目还有很多问题,比如:

  • 聊天记录不会保存,刷新页面之后聊天记录就会消失。
  • 没有用户认证和鉴权,谁都能输入房间号和用户名进入聊天室。

接下来,让我们继续完善这个「在线聊天室」,敬请期待!


🧐分享、点赞、在看,让我看到你们的热情!👇

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 州的先生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建虚拟环境
  • 安装依赖库
  • 创建项目
  • 配置项目
  • 创建视图
  • 定义路由
  • 编写 WebSocket 后端
  • 前端连接 WebSocket
  • 最后
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档