Python3.7 django3简单聊天程序开发

用django写简单聊天程序

1,环境

windows7
python3.7
django3
websockets
(pip install websockets)

2, 开启一个项目

django-admin.py startapp untitled

3,建立一个app

manage.py startapp chat

# untitled/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'chat',
]

4,建立模型

# chat/models.py
from django.db import models


class Room(models.Model):
    name = models.CharField(max_length=20)
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name


class Message(models.Model):
    name = models.CharField(max_length=20)
    text = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    room = models.ForeignKey(Room, on_delete=models.CASCADE)

    def __str__(self):
        return f'[name: {self.name}; date: {self.date}]: {self.text}'

5, 数据库迁移

python manage.py makemigrations chat
python manage.py migrate

你当然可以建立一个Room:

E:\DjangoProgram\untitled>python manage.py shell
Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from chat.models import *
>>> a = Room.objects.create(name='A chat room')

6,建立路由以及视图

chat下新建文件urls.py和forms.py,再在chat新建文件夹templates
并在templates新建room.html, create.html

# chat/urls.py
from django.urls import path
from . import views

app_name = 'chat'
urlpatterns = [
	# 创建房间的路由
    path('new_room', views.create_room, name='create'),
    # 聊天室
    path('/', views.enter_room, name='room'),
]

# chat/forms.py
from django import forms


class RoomForm(forms.Form):
    name = forms.CharField(max_length=20)

# chat/views.py
from django.shortcuts import render, get_object_or_404, reverse
from django.http import HttpResponseRedirect
# Create your views here.
from .models import *
from .forms import *


def enter_room(request, pk):
    room = get_object_or_404(Room, pk=pk)
    context = {
     
        'room': room.name,
        'all_messages': room.message_set.order_by('date'),
    }
    return render(request, 'room.html', context)


def create_room(request):
    form = RoomForm(request.POST or None)
    if form.is_valid():
        name = request.POST['name']
        r = Room.objects.create(name=name)
        return HttpResponseRedirect(reverse('chat:room', args=(r.pk, )))
    context = {
     
        'form': form
    }
    return render(request, 'create.html', context)

<html lang="zh">
<head><title>{
    { room }}title>head>
<body>
<div id="log">
    {% for all_message in all_messages %}
        <p>[name: {
    { all_message.name }} ; date: {
    { all_message.date|date }} {
    { all_message.date|time }}] {
    { all_message.text }}p>
    {% endfor %}
div>
<label for="inputname">name:label><input type="text" id="inputname">
<br/>
<label for="input">message:label><textarea id="input" style="width: 100%;height: 100px">textarea>
<br/>
<input type="button" id="submit" value="send">
body>
<script>
    const log = document.getElementById('log');
    // log用于记录信息
    const name = document.getElementById('inputname');
    // name字段
    const input = document.getElementById('input');
    // text字段
    const but = document.getElementById('submit');
    // 发送按钮
    // 建立webosckets对象
    const ws = new WebSocket('ws://'+window.location.hostname+':8181'+window.location.pathname);
    // 注意,websockets的服务端口与django的设置的不同!!!
    // 下面是客户端的websockets(等下我会展示服务端的)
    ws.onopen = function () {
      
        alert('connected....');
    };
    ws.onclose = function () {
      
        alert('closed');
    };
    ws.onmessage = function (ev) {
      
        const  data = JSON.parse(ev.data);
        // 当服务端有数据发送...
        const name = data['name'];
        const message = data['message'];
        let dt = Date();
        dt = dt.toLocaleString();
        const p = document.createElement('p');
        p.innerText = '[name: '+name+' ; date: '+dt+'] '+message;
        log.appendChild(p);
    };
    function send() {
      
        const n = name.value;
        const m = input.value;
        // 向服务端发送数据,用json打包
        ws.send(JSON.stringify({
      'name': n, 'message': m}))
    }
    but.onclick = function () {
      
        send();
        // 按钮按下执行
        input.value = '';
        // 清空
    }
script>
html>

<html lang="zh">
<head><title>Add roomtitle>head>
<body>
<form method="post" action="{% url 'chat:create' %}">
    {% csrf_token %}
    {
    { form.as_p }}
    <input type="submit" value="submit">
form>
body>
html>

最后:

# untitled/urls.py
from django.urls import path, include

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

7, 服务端websockets实现

不同于网上大部分用dwebsockets, channels
我选择用websockets写服务端
最激动人心也是最容易出问题的部分
在根目录下新建server.py

# server.py
import asyncio
import websockets
import json
import sys
import os
import django
sys.path.append(os.getcwd())
添加路径
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled.settings")
# 这个很重要不然等下在协程中访问数据库就会报错
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
django.setup()
from chat.models import *
# 记录登录用户
websocket_users = set()


async def recv_user_msg(websocket, path):
    print(path)
    # 解析路径,获取房间pk值
    # 注意用/区分路径后最后一个是''(读者可以试试)
    # 所以要取倒数第二个
    pk = path.split('/')[-2]
    room = Room.objects.get(pk=int(pk))
    while True:
        recv_text = await websocket.recv()
        # 解析数据
        data = json.loads(recv_text)
        # 写入数据库
        room.message_set.create(name=data['name'], text=data['message'])
        for i in websocket_users:
        	# 如果有用户与他在同一路将,那么发送信息(联系下面的看)
            if i[1] == path:
                await i[0].send(recv_text)


# 服务器端主逻辑
async def run(websocket, path):
    print(f'you are at path:{path}')
    while True:
        try:
            websocket_users.add((websocket, path))
            # 添加元组,第二个记录用户端的路径
            await recv_user_msg(websocket, path)
        except websockets.ConnectionClosed:
            try:
                websocket_users.remove((websocket, path))
                # 移除该用户的记录
            except KeyError:
                pass
            break
        except websockets.InvalidState:
            break
        except Exception as e:
            print(f'Exception :{e}')


def main():
    print("127.0.0.1:8181 websocket...")
    asyncio.get_event_loop().run_until_complete(websockets.serve(run, "127.0.0.1", 8181))
    asyncio.get_event_loop().run_forever()


if __name__ == '__main__':
   main()

这段代码我借鉴了网上的,根据需求改了一些

8,启动项目

一:python manage.py runserver
二:python server.py
记住,2个程序必须都有启动!!!
最后打开http://127.0.0.1:8000/chat/1
(前提你在前面建立了一个空房间。)
效果截图:
Python3.7 django3简单聊天程序开发_第1张图片
项目结构附图:
Python3.7 django3简单聊天程序开发_第2张图片
这个项目最大的难度就是搞websockets服务端
网上找了许多都没有用
希望对大家有帮助。
如果有问题大家可以指出来,谢谢(我也是个不是老司机。。)

你可能感兴趣的:(django,python)