Django中如何实现公共查询,避免通知数据在多页面重复查询
Django全局通知重复查询优化方案
以下是4种可落地的优化方案,按实现成本从低到高排序:
方案1:使用Django上下文处理器全局注入(最推荐)
上下文处理器会在每个请求的模板渲染前执行一次,将通知数据注入到所有模板的上下文里,整个请求周期只会查询1次数据库,无需修改每个视图的代码。
- 第一步:在你的app下新建
context_processors.py,写入以下代码:
from .models import Notification def user_notifications(request): # 未登录用户直接返回空 if not request.user.is_authenticated: return {} # 只查未读通知,可按需加排序、分页逻辑 notifications = Notification.objects.filter(user=request.user, is_read=False).order_by('-create_time')[:10] return { 'user_notifications': notifications, 'unread_notification_count': notifications.count() }
- 第二步:在
settings.py的TEMPLATES配置的OPTIONS.context_processors里加上你写的处理器:
TEMPLATES = [ { # 其他原有配置不变 'OPTIONS': { 'context_processors': [ # 原有默认处理器保留 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', # 新增你的处理器,替换为你实际的app名称 'your_app_name.context_processors.user_notifications', ], }, }, ]
- 第三步:直接在公共导航栏模板里使用
{{ user_notifications }}和{{ unread_notification_count }}变量即可,所有页面无需额外传参。
方案2:自定义包含模板标签
如果不想全局注入所有模板,可以专门给导航栏写一个包含标签,仅在导航栏组件渲染时查询一次数据,代码侵入性更低。
- 在app下的
templatetags目录新建notification_tags.py:
from django import template from ..models import Notification register = template.Library() @register.inclusion_tag('components/notification_bell.html') def render_notification_bell(user): if not user.is_authenticated: return {'notifications': [], 'unread_count': 0} notifications = Notification.objects.filter(user=user, is_read=False).order_by('-create_time')[:10] return { 'notifications': notifications, 'unread_count': notifications.count() }
- 新建导航栏通知组件模板
components/notification_bell.html,写铃铛图标的渲染逻辑,直接用上面返回的变量即可。 - 在公共导航栏模板里调用标签:
{% load notification_tags %}{% render_notification_bell request.user %}
方案3:增加用户级缓存进一步降低数据库压力
如果网站访问量较大,可以对通知查询结果加缓存,同一个用户的通知在缓存有效期内只会查一次数据库:
from django.core.cache import cache def user_notifications(request): if not request.user.is_authenticated: return {} # 用用户id作为缓存key,保证不同用户的通知隔离 cache_key = f'user_notifications_{request.user.id}' data = cache.get(cache_key) if not data: notifications = Notification.objects.filter(user=request.user, is_read=False).order_by('-create_time')[:10] data = { 'user_notifications': notifications, 'unread_notification_count': notifications.count() } # 缓存1分钟,可按需调整时长 cache.set(cache_key, data, 60) return data
- 注意:在用户产生新通知、用户标记通知已读时,要主动删除对应用户的缓存,保证数据实时性:
cache.delete(f'user_notifications_{user.id}')
方案4:前端本地存储+异步更新
如果你的项目支持前端路由跳转(比如使用Vue、React或者HTMX),可以在用户第一次访问页面时把通知数据存在localStorage,后续页面切换直接读本地数据,后台定期调用接口增量更新通知,或者用WebSocket主动推送新通知,完全避免重复查询。
内容的提问来源于stack exchange,提问作者sixovov947
相关产品推荐
相关产品推荐

