You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Django Channels从Celery后台任务向浏览器发送刷新指令?

嘿,我来帮你搞定这个问题!你已经走对了第一步——在Celery任务里发送Channels消息,接下来咱们一步步配置Consumer和前端,让页面能收到刷新信号。

第一步:创建Channels Consumer监听消息

首先在你的Django项目里新建一个consumers.py文件,写一个Consumer来监听你指定的频道组(Channels V2更推荐用频道组做广播,比单个Channel更灵活):

from channels.generic.websocket import AsyncWebsocketConsumer
import json

class RefreshConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        # 加入名为"my-background-task"的频道组
        await self.channel_layer.group_add(
            'my-background-task',
            self.channel_name
        )
        await self.accept()

    async def disconnect(self, close_code):
        # 断开连接时离开频道组
        await self.channel_layer.group_discard(
            'my-background-task',
            self.channel_name
        )

    # 定义处理刷新消息的方法,方法名要和发送的消息type字段对应
    async def refresh(self, event):
        # 把消息推送给前端
        await self.send(text_data=json.dumps({
            'type': 'refresh',
            'content': '任务完成,即将刷新页面'
        }))
第二步:修改Celery任务的消息发送逻辑

你原来的Channel.send写法在V2里不太推荐,改成用频道组发送消息,这样所有订阅该组的客户端都能收到:

from celery import shared_task
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

@shared_task
def my_task():
    import time
    time.sleep(5)  # 模拟长时间运行的任务
    channel_layer = get_channel_layer()
    # 用async_to_sync包装异步的group_send,适配Celery的同步环境
    async_to_sync(channel_layer.group_send)(
        'my-background-task',
        {
            'type': 'refresh',  # 这个字段要和Consumer里的方法名完全一致
            'content': '任务完成'
        }
    )
第三步:配置Channels路由和Channel层

在项目根目录新建routing.py,配置WebSocket的路由规则:

from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/refresh-notification/$', consumers.RefreshConsumer.as_asgi()),
]

然后在settings.py里补充Channels的核心配置:

# 指定ASGI应用入口
ASGI_APPLICATION = '你的项目名.routing.application'

# 配置Redis作为Channel层后端(需要先安装channels-redis:pip install channels-redis)
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],  # 确保Redis服务在运行
        },
    },
}
第四步:前端添加WebSocket连接

最后在需要刷新的页面里,加入前端代码建立WebSocket连接,收到消息后自动刷新:

// 建立WebSocket连接
const socket = new WebSocket('ws://' + window.location.host + '/ws/refresh-notification/');

// 监听后端发来的消息
socket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    if (data.type === 'refresh') {
        // 收到刷新指令,立即刷新页面
        window.location.reload();
    }
};

// 连接断开时自动重试
socket.onclose = function(e) {
    console.error('WebSocket连接断开,3秒后重试...');
    setTimeout(() => {
        window.location.reload();
    }, 3000);
};
小提示
  • 如果你的网站用HTTPS,记得把ws://改成wss://
  • 要是需要给特定用户推送消息,可以在Consumer的connect方法里,根据当前用户ID创建专属频道组(比如user_123),这样就能精准推送啦

这样一套流程走下来,当Celery任务完成时,就会给所有连接的前端发送刷新信号,页面自动更新~

内容的提问来源于stack exchange,提问作者Kritz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:26:30