在 Django 中跨文件调用已连接的 WebSocket 进行数据传送
在 Django 中跨文件调用已连接的 WebSocket 进行数据传送
在 Django 项目中,如果你想在其他文件中向已连接的 WebSocket 客户端发送数据,有几种实现方式。以下是基于 Django Channels 的解决方案:
方法一:使用 Channel Layers(推荐)
这是最标准的方式,适用于生产环境,支持分布式部署。
1. 配置 Channel Layers
在 settings.py 中:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("127.0.0.1", 6379)], # Redis 地址
},
},
}
安装所需包:
pip install channels-redis
2. 修改消费者 (consumers.py)
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
import json
class MyConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = "notification" # 组名
await self.channel_layer.group_add(
self.room_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.room_name,
self.channel_name
)
# 接收从组发来的消息
async def send_notification(self, event):
message = event['message']
await self.send(text_data=json.dumps({
'message': message
}))
3. 在其他文件中发送消息
在任何 Python 文件中(如 views.py、tasks.py 等):
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def send_ws_message(message):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
"notification", # 组名,与消费者中一致
{
"type": "send.notification", # 对应消费者中的方法名(点换成下划线)
"message": message
}
)
方法二:使用全局变量(仅适用于开发/单进程)
如果只是简单项目且单进程运行,可以使用全局变量存储连接(不推荐生产环境使用)。
1. 创建全局存储文件 (websocket_connections.py)
active_connections = set()
def add_connection(connection):
active_connections.add(connection)
def remove_connection(connection):
active_connections.discard(connection)
async def broadcast_message(message):
for connection in active_connections:
await connection.send(text_data=message)
2. 修改消费者
from .websocket_connections import add_connection, remove_connection, broadcast_message
class MyConsumer(AsyncWebsocketConsumer):
async def connect(self):
await self.accept()
add_connection(self)
async def disconnect(self, close_code):
remove_connection(self)
3. 在其他文件中发送消息
from .websocket_connections import broadcast_message
import asyncio
async def send_data():
await broadcast_message("Hello from another file!")
# 如果在同步上下文中调用
asyncio.run(send_data())
方法三:使用数据库信号或 Celery 任务
如果数据变化来自模型,可以使用 Django 信号:
from django.db.models.signals import post_save
from django.dispatch import receiver
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from .models import MyModel
@receiver(post_save, sender=MyModel)
def model_updated(sender, instance, **kwargs):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
"updates",
{
"type": "send.update",
"message": f"Model {instance.id} updated"
}
)
最佳实践建议
- 生产环境:使用 Channel Layers + Redis
- 开发环境:可以使用内存 Channel Layer
CHANNEL_LAYERS = { "default": { "BACKEND": "channels.layers.InMemoryChannelLayer" } } - 性能考虑:对于高频消息,考虑批处理或限制发送频率
- 安全性:确保只有授权用户才能接收消息
完整示例:从视图发送 WebSocket 消息
# views.py
from django.http import JsonResponse
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def send_message_view(request):
message = request.GET.get('message', 'Hello')
# 发送到 WebSocket
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
"notification",
{
"type": "send.notification",
"message": message
}
)
return JsonResponse({"status": "ok"})

浙公网安备 33010602011771号