使用Django 1.11与Python3.6,中间件捕获用户至外部函数失败求助
Django 1.11捕获当前用户失败的原因及解决办法
我来帮你捋捋这个问题哈,你遇到拿不到_user.value的情况,大概率是这几个原因导致的,咱们一步步拆解解决:
常见问题原因
- ThreadLocal使用时机不对:如果用
threading.local()存用户,但在模型初始化阶段(项目启动时)就调用get_current_user(),这时候根本没有请求上下文,自然拿不到值。 - 中间件顺序/写法错误:Django 1.11里,
request.user是由AuthenticationMiddleware填充的,如果你的自定义中间件放在它前面,那存的request.user还没被初始化,要么是匿名用户要么是None。 - 模型调用时机错误:模型是项目启动时就加载的,如果你在模型类定义时直接调用
get_current_user(),这时候还没有任何请求进来,肯定拿不到用户。
正确的实现步骤
1. 编写正确的用户捕获中间件
用threading.local()存用户,同时要在请求结束后清理,避免线程复用导致的脏数据:
import threading from django.utils.deprecation import MiddlewareMixin # 定义ThreadLocal对象存用户 _user = threading.local() class CurrentUserMiddleware(MiddlewareMixin): def process_request(self, request): # 确保request有user属性时才赋值,避免报错 _user.value = request.user if hasattr(request, 'user') else None def process_response(self, request, response): # 请求结束后清理用户数据 if hasattr(_user, 'value'): del _user.value return response def get_current_user(): # 用getattr避免属性不存在时报错,返回None兜底 return getattr(_user, 'value', None)
2. 配置中间件到正确位置
在settings.py里,把你的中间件放在AuthenticationMiddleware之后,保证request.user已经被填充:
# settings.py MIDDLEWARE = [ # ...其他系统中间件... 'django.contrib.auth.middleware.AuthenticationMiddleware', # 替换成你的中间件路径,比如'appname.middleware.CurrentUserMiddleware' 'your_app.middleware.CurrentUserMiddleware', # ...其他自定义中间件... ]
如果你的项目还在用旧的MIDDLEWARE_CLASSES,同样要放在AuthenticationMiddleware后面。
3. 在模型中正确调用get_current_user()
绝对不能在模型类定义时直接调用,要在请求上下文存在的方法里调用,比如save()方法或者信号处理函数:
from django.db import models from your_app.middleware import get_current_user class YourModel(models.Model): created_by = models.ForeignKey('auth.User', null=True, blank=True, on_delete=models.SET_NULL) # 其他字段... def save(self, *args, **kwargs): # 新增记录时自动设置创建者 if not self.pk: self.created_by = get_current_user() super().save(*args, **kwargs)
额外注意点
- 如果你用Celery之类的异步任务,不能直接用
get_current_user(),因为异步任务在单独的线程/进程里,和请求线程无关,要手动传递用户ID到任务里。 - 匿名用户访问时,
get_current_user()会返回AnonymousUser对象,你可以根据业务需求判断是否要过滤这种情况。 - 一定要在
process_response里清理_user.value,不然线程复用的时候可能会拿到上一个请求的用户数据,造成数据混乱。
内容的提问来源于stack exchange,提问作者André
相关产品推荐
相关产品推荐

