Python 如何将self对象传递给全局变量(Django视图)

Python 如何将self对象传递给全局变量(Django视图),python,django,performance,Python,Django,Performance,我正在为基于Django的web应用程序编写功能。在各种基于类的视图方法中,如果用户在ban列表中,我会触发一些功能。由于我在多个视图中重复此比较,因此我决定将其转换为一个全局变量—在任何基于类的视图之外—因此: isbanned = HellBanList.objects.filter(condemned_id=self.request.user.id).exists() 不幸的是,我遇到了错误:未定义名称“self”,即self对象在基于类的视图之外不可用。对于request.user和u

我正在为基于Django的web应用程序编写功能。在各种基于类的视图方法中,如果用户在ban列表中,我会触发一些功能。由于我在多个视图中重复此比较,因此我决定将其转换为一个全局变量—在任何基于类的视图之外—因此:

isbanned = HellBanList.objects.filter(condemned_id=self.request.user.id).exists()
不幸的是,我遇到了错误:
未定义名称“self”
,即self对象在基于类的视图之外不可用。对于
request.user
user
我也得到了类似的结果

是否有
self.request.user
的变通方法可以用来计算这样一个全局变量(对经过身份验证和未经身份验证的用户都有效)?我的目标是只计算一次请求用户是否是hellban列表的一部分,然后在需要时使用该信息


或者,由于我在这里没有预见到的问题,我应该避免这样做吗?

您不应该指望
请求
来执行查询。您应该使用参数user编写util功能,如下所示:

def is_banned(user):
    return HellBanList.objects.filter(condemned_id=user.id).exists()
然后,当您需要检查时,请执行以下操作:

user_is_banned = is_banned(self.request.user)

首先,使用全局变量不是线程安全的。想象一下,两个请求同时被处理。第二个请求可能会在第一个请求完成之前覆盖
isbanked
,导致第一个请求被错误处理

若我是你们的话,我会写一篇文章,评估每个请求是否只禁止用户一次。然后将此信息存储在请求中:

class CalculateUserBannedMiddleware(object):

    def process_request(self, request):
        request.user_banned = HellBanList.objects.filter(condemned_id=request.user.id).exists()
需要在
django.contrib.auth.middleware.AuthenticationMiddleware
之后定义中间件类,以便能够访问
请求。用户
属性:

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'myapp.CalculateUserBannedMiddleware'
在代码的其余部分,您可以使用
request.user\u banked
检查当前用户是否被禁止。这样,每个请求只计算一次标志


编辑:

如果延迟计算
user\u
,甚至可以使解决方案更智能。这样,对于不需要此标志的请求,您就不会有任何开销

实现延迟求值的一种方法是将对象与
\uuuubool\uuuu
方法(Python 3)或
\uuuuuuuuuuu非零方法(Python 2)一起使用

Python 3的示例实现:

class LazyUserBannedFlag(object):

    user_banned = None

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

    def __bool__(self):
        if self.user_banned is None:
            user_id = self.request.user.id
            self.user_banned = HellBanList.objects.filter(condemned_id=user_id).exists()
        return self.user_banned


class CalculateUserBannedMiddleware(object):

    def process_request(self, request):
        request.user_banned = LazyUserBannedFlag(request)

谢恩,谢谢你的提示!问:我希望只执行一次“exists()”DB查询,然后在任何地方使用它。在您的解决方案中,这一目标会实现吗?还是每次我计算
用户是否被禁止时,它都会执行一个新的DB查询?
?它会执行多次,但我相信执行
exists()
是一种廉价的数据库操作。如果你真的想保存结果,你需要使用django
session
或者内存中的工具,比如
redis
。嘿,Dawid,你能不能修改一下你的答案中的一些完整性:?
user
在你编写的中间件代码中没有定义。那应该是
request.user
对吗?你是对的,应该是
request.user
。我修好了。经过一番思考,我也想出了更聪明的解决办法。