?目的:实现有新模型创建的时候自动通知浏览器刷新模型列表
本例子实现了,在admin新上传一个文档的时候,通知客户端
盗用一张介绍Websocket的图

1. 建一个 Django 项目,或者下载我的 Django base 项目
git clone git@github.com:chunkai-meng/base-django.git
2. 安装 channels 和 channels-redis
cd base-django/proj
pipenv install channels channels-redis
docker run --name websocket-redis -p 6379:6379 -d redis
3. 加入 Channel 到 INSTALLED_APPS & 添加 CHANNEL_LAYERS 到 settings
# settings.py
INSTALLED_APPS = [
'channels',
# ...
]
....
ASGI_APPLICATION = "proj.routing.application"
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("localhost", 6379)],
},
},
}
4. Code files
- proj/routing.py - already mentioned in settings.py as
ASGI_APPLICATION, which direct all the WebSocket request to the right consumers.
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from notification.comusers import NotificationConsumer
application = ProtocolTypeRouter({
"websocket": URLRouter([
path("notifications/", NotificationConsumer),
]),
})
- notification/consumers.py - an action handler to establish handshake, receive and send msg to the client.
from channels.generic.websocket import AsyncJsonWebsocketConsumer
class NotificationConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
await self.channel_layer.group_add('gossip', self.channel_name)
async def disconnect(self, code):
await self.channel_layer.group_discard('gossip', self.channel_name)
async def name_gossip(self, event):
await self.send_json(event)
- document/signals.py - a hook to send msg to the channel listened by consumer
from .models import Document
from django.db.models.signals import pre_save
from django.dispatch import receiver
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
# hook to be called whenever a Document is saved.
@receiver(pre_save, sender=Document)
def notify_post_save(sender, **kwargs):
if "instance" in kwargs:
instance = kwargs["instance"]
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
"gossip", {
"type": "name.gossip",
"event": "New Document",
"sender": instance.owner.username,
"message": instance.name
}
)
- document/apps.py - register the signal when the app is ready
from django.apps import AppConfig
class DocumentConfig(AppConfig):
name = 'document'
verbose_name = 'Documents'
def ready(self):
import document.signals


个人理解:
- Channel 是个管道,用来异步传递消息,需要 pip install
- Redis 是后端,要启动好,并且 localhost:6379 能访问,反正要跟设置里的一致
- Settings 里定义了 WebSocket 的请求都去找 routing.py
routing.py里定义了 一个 consumer 路径在notifications/所以一会 WebSocket 客户端要去访问这里NotificationConsumer就是一个标准的 Consumernotify_post_save是一个测试用的钩子,目的是异步的出发消息发送到 Channel,然后回给客户端
有不对的地方欢迎留言
334



被折叠的 条评论
为什么被折叠?



