如何在Django自定义工具函数中使用request.session且不传递request对象?
解决Django自定义工具函数中访问request对象的问题
嘿,作为Django新手碰到这个问题太正常啦!我来给你讲讲几种不用从视图里直接传request就能在util.py里访问session的方法,还有为啥你之前导入HttpRequest没用~
为什么导入HttpRequest不行?
首先得搞清楚:django.http.HttpRequest只是一个请求类的模板,你直接用它根本拿不到当前正在处理用户请求的那个真实request对象——那个对象是Django在接收到浏览器请求时动态创建的,只有在视图、中间件这些请求处理流程里才能直接获取到。空的HttpRequest实例自然没有session属性啦。
方法一:用中间件存储当前请求(最推荐的方式)
我们可以写一个简单的中间件,把当前请求存在线程局部变量里,这样整个请求处理过程中,任何地方都能拿到这个request对象。
步骤1:创建中间件文件
在你的app目录下新建middleware.py,写入以下代码:
import threading # 线程局部变量,每个线程存自己的request,避免多线程冲突 _local = threading.local() class RequestMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 把当前请求存到线程局部变量里 _local.request = request # 继续处理请求 response = self.get_response(request) # 请求处理完后清理,避免线程复用导致的问题 del _local.request return response # 提供一个获取当前请求的工具函数 def get_current_request(): return getattr(_local, 'request', None)
步骤2:配置中间件
打开项目的settings.py,找到MIDDLEWARE列表,把刚才的中间件加进去(注意顺序,建议放在其他中间件的后面):
MIDDLEWARE = [ # 其他默认中间件... 'your_app_name.middleware.RequestMiddleware', # 替换成你的app名称 ]
步骤3:在util.py里使用
修改你的processData函数:
from .middleware import get_current_request def processData(data=None): # 获取当前请求对象 request = get_current_request() # 处理没有请求的情况(比如后台任务调用这个函数) if request is None: items = {} else: items = request.session.get('items', {}) # 追加数据 items.update(data or {}) return items
这种方法的好处是不用改任何视图的调用逻辑,缺点是如果在非请求上下文(比如Celery异步任务)里调用这个函数,get_current_request会返回None,所以一定要加判断哦。
方法二:传递session数据而非整个request
如果你不想用中间件,其实可以退一步——不用传整个request,只传需要的items数据就行,这样也能达到目的。
修改util.py:
def processData(data=None, current_items=None): # 如果没传current_items,就用空字典 items = current_items or {} items.update(data or {}) return items
在views.py里调用:
from .util import processData def your_view(request): # 先从session拿到当前的items current_items = request.session.get('items', {}) # 调用processData时传入current_items updated_items = processData(data=your_data, current_items=current_items) # 最后把更新后的items存回session request.session['items'] = updated_items # 其他视图逻辑...
这种方法更直观,没有线程安全问题,也不用依赖中间件,唯一的小麻烦是调用时要多传一个参数。
内容的提问来源于stack exchange,提问作者Jayakrishnan
相关产品推荐
相关产品推荐

