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

Django+React+uWSGI应用:数据库变更触发前端重载的最优方案

问题解答

原轮询方案是否合理?

短期应急可以用,但非常不推荐长期使用。每秒轮询会带来几个严重问题:

  • 服务器承受大量无效请求,用户量上升后,API接口和数据库会被频繁空查询拖垮;
  • 最多1秒的延迟是硬伤,没法做到真正的实时;
  • 前端频繁发起请求会增加客户端资源消耗,影响用户体验。

更优实现方案

结合你的Django+React+uWSGI架构,推荐以下几种实时推送方案,从易到难排序:

1. Server-Sent Events (SSE):最简单向推送

SSE是基于HTTP的单向推送协议,服务器主动给前端发消息,不需要额外协议,uWSGI也能支持(只需配置长连接)。

实现要点:

  • Django端:写一个返回text/event-stream类型的视图,保持长连接,当数据库有变更时向客户端发送事件:

    from django.http import StreamingHttpResponse
    import time
    from myapp.models import MyTable
    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    # 生产环境建议用Redis/消息队列替代全局变量,避免多进程数据不一致
    has_change = False
    
    @receiver(post_save, sender=MyTable)
    def on_table_change(sender, instance, created, **kwargs):
        global has_change
        has_change = True
    
    def sse_stream(request):
        def event_generator():
            global has_change
            while True:
                if has_change:
                    # 自定义事件内容,比如触发指定JS函数的指令
                    yield f"data: reload\n\n"
                    has_change = False
                time.sleep(0.5)  # 降低轮询标记的频率
        return StreamingHttpResponse(
            event_generator(), 
            content_type='text/event-stream'
        )
    

    uWSGI配置需开启http-keepalive,避免长连接被强制断开。

  • React端:用EventSource监听SSE流,收到事件后执行对应操作:

    useEffect(() => {
        const eventSource = new EventSource('/sse-stream/');
        eventSource.onmessage = (event) => {
            if (event.data === 'reload') {
                // 执行重载或指定JS函数
                window.location.reload();
                // 或者调用自定义函数:myCustomFunction();
            }
        };
        return () => eventSource.close();
    }, []);
    
  • 处理直接MySQL命令的场景:如果管理员绕开Django直接操作数据库,给mytable加MySQL触发器,当有INSERT/UPDATE/DELETE时调用Django接口标记变更:

    DELIMITER //
    CREATE TRIGGER after_mytable_change
    AFTER INSERT ON mytable
    FOR EACH ROW
    BEGIN
        -- 生产环境建议用消息队列替代直接HTTP请求,避免触发器阻塞
        CALL sys.http_get('http://your-django-server/api/mark-change/');
    END //
    DELIMITER ;
    

2. WebSocket:双向实时通信

如果未来需要前端给服务器发消息的交互场景,WebSocket更合适。Django可以用Channels库实现WebSocket服务,搭配ASGI服务器(比如Daphne)与uWSGI共存(uWSGI处理HTTP请求,Daphne处理WebSocket)。

实现要点:

  • Django端:配置Channels,定义WebSocket消费者,监听数据库变更信号并推送消息:

    # consumers.py
    from channels.generic.websocket import AsyncWebsocketConsumer
    import json
    from myapp.models import MyTable
    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
    
    channel_layer = get_channel_layer()
    
    @receiver(post_save, sender=MyTable)
    def send_change_notification(sender, instance, created, **kwargs):
        async_to_sync(channel_layer.group_send)(
            'table_updates',
            {'type': 'send_update', 'message': 'reload'}
        )
    
    class TableUpdateConsumer(AsyncWebsocketConsumer):
        async def connect(self):
            await self.channel_layer.group_add('table_updates', self.channel_name)
            await self.accept()
    
        async def disconnect(self, close_code):
            await self.channel_layer.group_discard('table_updates', self.channel_name)
    
        async def send_update(self, event):
            message = event['message']
            await self.send(text_data=json.dumps({'message': message}))
    
  • React端:用WebSocket连接,收到消息后执行操作:

    useEffect(() => {
        const socket = new WebSocket('ws://your-django-server/ws/table-updates/');
        socket.onmessage = (event) => {
            const data = JSON.parse(event.data);
            if (data.message === 'reload') {
                window.location.reload();
                // 或调用自定义函数
            }
        };
        return () => socket.close();
    }, []);
    
  • 直接MySQL命令的处理:同样用MySQL触发器调用Django接口,触发信号推送WebSocket消息。

3. 基于Redis Pub/Sub的中转方案

如果不想改动Django的Web服务架构,可以用Redis的发布订阅功能:

  • 数据库变更时(Django信号或MySQL触发器),向Redis的指定频道发布消息;
  • Django写一个后台进程(或用Celery)订阅该频道,收到消息后通过SSE/WebSocket推给前端;
  • 这种方案适合多实例部署的场景,避免单服务器的推送局限。

方案选择建议

  • 优先选SSE:配置最简单,不需要额外服务,适合单纯的服务器推送场景;
  • 如果需要双向交互,选WebSocket + Channels;
  • 多实例部署选Redis Pub/Sub + SSE/WebSocket。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:57:20