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

Django中Webhook调用时Messages框架消息无法前端显示的解决方法

解决Django Webhook触发后全局显示告警消息的问题

原代码的核心问题是:Django的messages框架依赖**用户会话(Session)**存储消息,而Grafana发起的Webhook请求没有绑定任何用户会话,消息只会被关联到Webhook的请求上下文,无法被普通用户的页面请求获取到。要实现全局消息展示,需要将告警消息存储到全局可访问的介质,再在用户访问页面时读取并显示。

以下是两种可行的实现方案:

方案一:使用Django缓存存储临时消息

缓存适合存储临时告警,轻量高效,推荐用于不需要持久化的场景。

1. 配置缓存(以Redis为例)

先安装依赖包redis和django-redis,然后在settings.py中配置:

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

2. 修改Webhook视图函数

替换原有的messages调用,将告警数据存入缓存:

from django.core.cache import cache
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
import json

@csrf_exempt
@require_POST
def hoof_alert(request):
    json_rx = json.loads(request.body.decode("utf-8"))
    if json_rx["alerts"][0]["status"] == "firing":
        alert_data = {"type": "error", "text": "Alarm fired"}
    else:
        alert_data = {"type": "success", "text": "No more alarm"}
    # 存储告警,设置30分钟过期(可按需调整)
    cache.set("global_alert", alert_data, timeout=1800)
    return HttpResponse(status=200)

3. 在前端页面读取消息

方式A:通过视图注入到用户会话消息

# views.py
from django.core.cache import cache
from django.contrib import messages
from django.shortcuts import render

def frontend_page(request):
    alert = cache.get("global_alert")
    if alert:
        if alert["type"] == "error":
            messages.error(request, alert["text"])
        elif alert["type"] == "success":
            messages.success(request, alert["text"])
        # 可选:读取后删除缓存,避免重复显示;若需所有用户都看到则保留
        # cache.delete("global_alert")
    return render(request, "frontend_page.html")

模板中按原有逻辑渲染messages即可:

{% if messages %}
    {% for message in messages %}
        <div class="alert alert-{{ message.tags }}">
            {{ message }}
        </div>
    {% endfor %}
{% endif %}

方式B:直接在模板中读取缓存

{% load cache %}
{# 缓存5分钟,减少缓存查询频率 #}
{% cache 300 global_alert %}
    {% with alert=cache.get("global_alert") %}
        {% if alert %}
            <div class="alert alert-{{ alert.type }}">
                {{ alert.text }}
            </div>
        {% endif %}
    {% endwith %}
{% endcache %}

方案二:使用数据库存储持久化消息

如果需要保留告警历史,或缓存方案不满足需求,可采用数据库存储全局告警。

1. 创建告警模型

# models.py
from django.db import models

class GlobalAlert(models.Model):
    TYPE_CHOICES = (
        ("error", "Error"),
        ("success", "Success"),
    )
    type = models.CharField(max_length=10, choices=TYPE_CHOICES)
    text = models.TextField()
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        get_latest_by = "updated_at"
        verbose_name = "全局告警"
        verbose_name_plural = "全局告警"

执行迁移命令:

python manage.py makemigrations
python manage.py migrate

2. 修改Webhook视图函数

更新或创建全局告警记录:

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
import json
from .models import GlobalAlert

@csrf_exempt
@require_POST
def hoof_alert(request):
    json_rx = json.loads(request.body.decode("utf-8"))
    if json_rx["alerts"][0]["status"] == "firing":
        alert_type = "error"
        alert_text = "Alarm fired"
    else:
        alert_type = "success"
        alert_text = "No more alarm"
    # 固定主键确保全局只有一条最新告警记录
    GlobalAlert.objects.update_or_create(
        pk=1,
        defaults={"type": alert_type, "text": alert_text}
    )
    return HttpResponse(status=200)

3. 在前端页面读取消息

方式A:通过视图注入到用户会话消息

# views.py
from django.contrib import messages
from django.shortcuts import render
from .models import GlobalAlert

def frontend_page(request):
    try:
        alert = GlobalAlert.objects.latest()
        if alert.type == "error":
            messages.error(request, alert.text)
        else:
            messages.success(request, alert.text)
    except GlobalAlert.DoesNotExist:
        pass
    return render(request, "frontend_page.html")

方式B:直接在模板中渲染

{% with latest_alert=GlobalAlert.objects.latest %}
    {% if latest_alert %}
        <div class="alert alert-{{ latest_alert.type }}">
            {{ latest_alert.text }}
        </div>
    {% endif %}
{% endwith %}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 00:12:08