1.数据库连接:database_sync_to_async
要使用它,请在单独的函数或方法中编写ORM查询,然后database_sync_to_async像这样调用它:
from channels.db import database_sync_to_async
async def connect(self):
self.username = await database_sync_to_async(self.get_name)()
def get_name(self):
return User.objects.all()[0].name
也可以将它用作装饰者:
from channels.db import database_sync_to_async
async def connect(self):
self.username = await self.get_name()
@database_sync_to_async
def get_name(self):
return User.objects.all()[0].name
2.WebsocketConsumer函数说明:
# chat/consumers.py
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json
class ChatConsumer(WebsocketConsumer):
def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
async_to_sync(self.channel_layer.group_add)(
self.room_group_name,
self.channel_name
)
self.accept()
def disconnect(self, close_code):
# Leave room group
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
def chat_message(self, event):
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({
'message': message
}))
-
def connect(self):
连接时触发 -
def disconnect(self, close_code):
断开时触发 -
def receive(self, text_data):
接收消息时触发 -
self.channel_layer.group_add( self.room_group_name, self.channel_name )
将新的连接加入到群组 -
self.channel_layer.group_discard( self.room_group_name, self.channel_name )
将关闭的连接从群组中移除 -
self.channel_layer.group_send)( self.room_group_name, { 'type': 'chat_message', 'message': message }
信息群发 -
self.send(text_data=json.dumps({ 'message': message }))
单发消息 -
self.scope [ 'url_route'] [ 'kwargs'] [ 'ROOM_NAME']
每个用户都有一个范围,其中包含有关其连接的信息,特别是包括URL路由中的任何位置或关键字参数以及当前经过身份验证的用户(如果有) -
self.room_group_name ='chat_%s'%self.room_name
直接从用户指定的房间名称构造Channels组名称,不进行任何引用或转义。
组名只能包含字母,数字,连字符和句点。因此,此示例代码将在具有其他字符的房间名称上失败。 -
async_to_sync(.....)
包装器是必需的,因为ChatConsumer是同步WebsocketConsumer,但它调用异步通道层方法。(所有通道层方法都是异步的。) -
self.accept()
接受WebSocket连接。
如果不在connect()方法中调用accept(),则拒绝并关闭连接。例如,您可能希望拒绝连接,因为请求的用户无权执行请求的操作。
如果您选择接受连接,建议将accept()作为connect()中的最后一个操作。
3.异步
# chat/consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
import json
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
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
async def chat_message(self, event):
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
4.setting配置
ASGI_APPLICATION = "websocket.routing.application"
redis_host = os.environ.get('REDIS_HOST', 'localhost')
CHANNEL_PREFIX = "asgi:"
CHANNEL_LAYERS = {
"default": {
# This example app uses the Redis channel layer implementation channels_redis
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [(redis_host, 6379)],
'prefix': CHANNEL_PREFIX,
},
},
}
在项目目录下创建文件asgi.py
import os
import django
from channels.routing import get_default_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "NetWorkMonitor.settings")
django.setup()
application = get_default_application()
5.创建app 编写websocket服务
python manage.py startapp websocket
:创建websocket
应用,在websocket
应用下创建routing.py
和 consumers.py
文件;
routing.py
:他是用来指定WebSocket表单的位置,当有WebSocket请求访问时,就会根据这个路径找到相应表单,调用相应的函数进行处理
from channels.auth import AuthMiddlewareStack
from channels.routing import URLRouter, ProtocolTypeRouter
from django.urls import path
from .consumers import EchoConsumer
application = ProtocolTypeRouter({
"websocket": AuthMiddlewareStack(
URLRouter([
path(r"ws/", EchoConsumer),
# path(r"stats/", StatsConsumer),
])
)
})
consumers.py
:consumers.py就相当于新的view.py,编写逻辑
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from channels.layers import get_channel_layer
channel_layer = get_channel_layer()
class EchoConsumer(WebsocketConsumer):
def connect(self):
# 创建channels group, 命名为:用户名,并使用channel_layer写入到redis
async_to_sync(self.channel_layer.group_add)(self.scope['user'].username, self.channel_name)
# 返回给receive方法处理
self.accept()
def receive(self, text_data):
async_to_sync(self.channel_layer.group_send)(
self.scope['user'].username,
{
"type": "user.message",
"text": text_data,
},
)
def user_message(self, event):
# 消费
self.send(text_data=event["text"])
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(self.scope['user'].username, self.channel_name)