Django 3.2如何在视图内外函数中获取用户ID实现专属缓存?
在Django 3.2中实现请求周期内全局获取用户ID的方案
可以通过**线程本地存储(threading.local)**结合Django中间件实现请求周期内全局获取用户ID,完全不需要修改现有函数的参数。如果你的项目用到异步视图,也可以改用contextvars适配协程环境,以下是具体实现步骤:
1. 编写请求上下文工具模块
创建工具文件(比如utils/request_context.py),用来存储和获取当前请求的用户:
import threading # 线程本地存储,每个请求线程独立持有数据 _local = threading.local() def set_current_user(user): """设置当前请求的用户""" _local.user = user def get_current_user_id(): """获取当前请求用户的ID,未登录则返回None""" user = getattr(_local, 'user', None) return user.id if user else None
如果项目包含异步视图,改用contextvars(Django 3.2支持)适配协程:
import contextvars # 协程上下文变量,每个协程独立持有数据 current_user = contextvars.ContextVar('current_user', default=None) def set_current_user(user): current_user.set(user) def get_current_user_id(): user = current_user.get() return user.id if user else None
2. 实现中间件注入用户信息
创建中间件文件(比如middleware.py),在请求进入时自动设置当前用户:
from django.utils.deprecation import MiddlewareMixin from .utils.request_context import set_current_user class CurrentUserMiddleware(MiddlewareMixin): def process_request(self, request): # 仅在用户已认证时设置,未登录则设为None if request.user.is_authenticated: set_current_user(request.user) else: set_current_user(None) # 兼容异步视图的处理 async def __call__(self, request): if request.user.is_authenticated: set_current_user(request.user) else: set_current_user(None) response = await self.get_response(request) return response
然后在settings.py的MIDDLEWARE列表中添加该中间件,必须放在AuthenticationMiddleware之后,确保request.user已被正确认证:
MIDDLEWARE = [ # 其他中间件... 'django.contrib.auth.middleware.AuthenticationMiddleware', 'your_app_name.middleware.CurrentUserMiddleware', # 替换为你的应用名 # 其他中间件... ]
3. 在缓存中使用用户ID
现在你可以在任何函数(包括视图外的工具函数)中直接调用get_current_user_id(),结合django-cache-memoize生成用户专属的缓存键:
from cache_memoize import cache_memoize from .utils.request_context import get_current_user_id # 生成带用户ID的缓存前缀,确保每个用户的缓存独立 @cache_memoize(3600, key_prefix=lambda: f"user_{get_current_user_id()}") def fetch_user_specific_data(): # 这里返回用户专属的业务数据 return some_database_query()
注意事项
- 未登录用户:
get_current_user_id()会返回None,此时可根据需求决定是否缓存(比如给未登录用户设置固定前缀,或者跳过缓存)。 - 线程/协程安全:线程本地存储和contextvars都是当前请求上下文隔离的,不会出现多请求数据混乱的问题。
- 缓存键唯一性:通过
user_{user_id}作为前缀,确保每个用户的缓存键完全独立,不会互相覆盖。
内容的提问来源于stack exchange,提问作者thisisnotatest
相关产品推荐
相关产品推荐

