Skip to main content
 首页 » 编程设计

python之如何将自身对象传递给全局变量(Django View )

2024年08月23日38leader

我正在写 hellban我基于 Django 的网络应用程序的功能。在各种基于类的 View 方法中,如果用户在禁止列表中,我会触发一些功能。由于我在多个 View 中重复这种比较,因此我决定将它变成一个全局变量 - 在任何基于类的 View 之外 - 因此:

isbanned = HellBanList.objects.filter(condemned_id=self.request.user.id).exists() 

不幸的是,我遇到了错误:name 'self' is not defined,即 self 对象在基于类的 View 之外不可用。 request.user 和 user 也得到了类似的结果。

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

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

请您参考如下方法:

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

如果我是你,我会写 middleware class评估用户是否仅在每个请求中被禁止一次。然后将此信息存储在请求中:

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 之后定义,以便能够访问 request.user 属性:

MIDDLEWARE_CLASSES = ( 
    ... 
    'django.contrib.auth.middleware.AuthenticationMiddleware', 
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 
    'myapp.CalculateUserBannedMiddleware' 

在您的其余代码中,您可以使用 request.user_banned 来检查当前用户是否被禁止。这样每个请求只计算一次标志。


编辑:

如果延迟计算 user_banned,您甚至可以使解决方案更智能。这样您就不会为不需要此标志的请求产生任何开销。

实现惰性求值的一种方法是使用带有__bool__ 方法(Python 3)或__nonzero__ 方法(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)