首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django中间件:在数据库查询包装器中访问RecursionError时的`self.request.user`

Django中间件:在数据库查询包装器中访问RecursionError时的`self.request.user`
EN

Stack Overflow用户
提问于 2022-05-24 03:36:00
回答 1查看 159关注 0票数 1

我正在一个带有Postgres的示例django应用程序上测试我的数据库查询中间件(姜戈博士)。应用程序是炊具样板。我使用中间件的目标只是记录所有数据库查询的用户ID。使用Python3.9和Django3.2.13。我的中间件代码如下:

代码语言:javascript
复制
# Middleware code
import logging

import django
from django.db import connection

django_version = django.get_version()
logger = logging.getLogger(__name__)


class Logger:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        with connection.execute_wrapper(QueryWrapper(request)):
            return self.get_response(request)

class QueryWrapper:
    def __init__(self, request):
        self.request = request

    def __call__(self, execute, sql, params, many, context):
        # print(self.request.user)
        return execute(sql, params, many, context)

如果print(self.request.user.id)被注释掉,一切都会正常运行。但是,我发现取消注释或与user字段在self.request对象中的任何类型的交互都会导致递归错误:

代码语言:javascript
复制
RecursionError at /about/
maximum recursion depth exceeded
Request Method: GET
Request URL:    http://127.0.0.1:8000/about/
Django Version: 3.2.13
Exception Type: RecursionError
Exception Value:    
maximum recursion depth exceeded
Exception Location: /opt/homebrew/lib/python3.9/site-packages/django/db/models/sql/query.py, line 192, in __init__
Python Executable:  /opt/homebrew/opt/python@3.9/bin/python3.9
Python Version: 3.9.13

在错误页面中,后面是以下错误的多次重复:

代码语言:javascript
复制
During handling of the above exception ('SessionStore' object has no attribute '_session_cache'), another exception occurred:
/opt/homebrew/lib/python3.9/site-packages/django/contrib/sessions/backends/base.py, line 233, in _get_session
            return self._session_cache …

During handling of the above exception ('SessionStore' object has no attribute '_session_cache'), another exception occurred:
/opt/homebrew/lib/python3.9/site-packages/django/contrib/sessions/backends/base.py, line 233, in _get_session
            return self._session_cache …

通过咨询其他这样的帖子,访问user字段似乎应该工作得很好。我已经检查了django_session表的存在,我的中间件也位于我的中间件的最底层(包括"django.contrib.sessions.middleware.SessionMiddleware""django.contrib.auth.middleware.AuthenticationMiddleware")。

这里怎么了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-24 04:00:14

编写self.request.user时会发生以下情况

  1. 将检查request是否具有属性_cached_user,如果存在缓存的用户,则返回缓存的用户,如果没有,则在请求中调用auth.get_user
  2. Django使用会话密钥检查会话,以获得当前用户使用的身份验证后端。在这里,如果使用基于数据库的会话,则会触发数据库查询
  3. 使用上面的身份验证后端Django可以使用数据库查询来获取当前用户的ID。

如前所述,除非缓存命中,否则此进程将导致数据库查询。

使用数据库工具,您已经在数据库查询周围安装了一个包装器,问题是这个包装器本身正在尝试进行更多的查询(试图获取当前用户),从而导致它调用自己。一种解决方案是在安装包装器功能之前获取当前用户:

代码语言:javascript
复制
class Logger:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        _user_authenticated = request.user.is_authenticated # Making sure user is fetched (Lazy object)
        with connection.execute_wrapper(QueryWrapper(request)):
            return self.get_response(request)


class QueryWrapper:
    def __init__(self, request):
        self.request = request

    def __call__(self, execute, sql, params, many, context):
        print(self.request.user)
        return execute(sql, params, many, context)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72356939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档