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
相关产品推荐
相关产品推荐

