如何安全地访问 Django 模型中的请求对象
How to safely access request object in Django models
我想做什么:
我正在尝试访问我的 Django 模型中的请求对象,以便我可以使用 request.user
.
获取当前登录的用户
我试过的:
我在 this 网站上发现了黑客攻击。但是评论中有人指出在生产时不要这样做。
我还尝试重写模型的 __init__
方法,就像 this post 中提到的那样。但是我得到了一个 AttributeError: 'RelatedManager' object has no attribute 'request'
Models.py:
class TestManager(models.Manager):
def user_test(self):
return self.filter(user=self.request.user, viewed=False)
class Test(models.Model):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(Test, self).__init__(*args, **kwargs)
user = models.ForeignKey(User, related_name='test')
viewed = models.BooleanField(default=False)
objects = TestManager()
I trying to access request object in my Django models so that I can get the currently logged in user with request.user
.
好吧,问题是模型本身 而不是 在请求的上下文中使用。例如,一个经常定义 custom commands 来做簿记,或者可以定义一个 API,例如用户 不 在场。 Django 方法的想法是 模型应该 而不是 是请求感知的 。模型定义“业务逻辑”层:模型定义实体及其交互方式。如果不尊重这些层,就会使应用程序容易出现很多问题。
您提到的博客旨在创建他们所谓的全局状态(这是一个严重的anti-patten):当view 进行调用,这样您就可以在模型层中获取该对象。这种方法存在一些问题:首先,如前所述,并非所有用例都是视图,因此并非所有用例都通过中间件。因此,在获取属性时,该属性可能不存在。
并且不保证请求对象确实是视图的请求对象。例如,我们有可能将模型层与不通过中间件的命令一起使用,在这种情况下,我们应该使用先前的视图请求(因此可能与不同的用户一起使用)。如果服务器并发处理多个请求,视图也可能会看到几纳秒后到达的请求,从而再次接收错误的用户。身份验证中间件也可能是有条件的,因此并非所有请求都具有 user
属性。简而言之,有足够多的场景可能会失败,结果可能会很严重:人们看到、编辑或删除他们不“拥有”的数据(无权查看、编辑或删除)。
因此您 需要将 request
或 user
对象传递给 user_test
方法。例如:
from django.http import HttpRequest
class TestManager(models.Manager):
def user_test(self<b>, request_or_user</b>):
if isinstance(request_or_user, HttpRequest):
return self.filter(user=request_or_user.user, viewed=False)
else:
return self.filter(user=request_or_user, viewed=False)
因此必须将 request
对象从视图传递给函数。甚至这也不是真正的纯粹。真正的 pure 方法只接受 user
对象:
class TestManager(models.Manager):
def user_test(self<b>, user</b>):
return self.filter(user=user, viewed=False)
因此在一个视图中可以将其用作:
def some_view(request):
some_tests = Test.objects.user_test(request.user)
# ...
# return Http response
例如,如果我们想用这个查询集渲染一个模板,我们可以像这样传递它:
def some_view(request):
some_tests = Test.objects.user_test(request.user)
# ...
return render(request, 'my_template.html', {'some_tests': some_tests})
我想做什么:
我正在尝试访问我的 Django 模型中的请求对象,以便我可以使用 request.user
.
我试过的:
我在 this 网站上发现了黑客攻击。但是评论中有人指出在生产时不要这样做。
我还尝试重写模型的 __init__
方法,就像 this post 中提到的那样。但是我得到了一个 AttributeError: 'RelatedManager' object has no attribute 'request'
Models.py:
class TestManager(models.Manager):
def user_test(self):
return self.filter(user=self.request.user, viewed=False)
class Test(models.Model):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(Test, self).__init__(*args, **kwargs)
user = models.ForeignKey(User, related_name='test')
viewed = models.BooleanField(default=False)
objects = TestManager()
I trying to access request object in my Django models so that I can get the currently logged in user with
request.user
.
好吧,问题是模型本身 而不是 在请求的上下文中使用。例如,一个经常定义 custom commands 来做簿记,或者可以定义一个 API,例如用户 不 在场。 Django 方法的想法是 模型应该 而不是 是请求感知的 。模型定义“业务逻辑”层:模型定义实体及其交互方式。如果不尊重这些层,就会使应用程序容易出现很多问题。
您提到的博客旨在创建他们所谓的全局状态(这是一个严重的anti-patten):当view 进行调用,这样您就可以在模型层中获取该对象。这种方法存在一些问题:首先,如前所述,并非所有用例都是视图,因此并非所有用例都通过中间件。因此,在获取属性时,该属性可能不存在。
并且不保证请求对象确实是视图的请求对象。例如,我们有可能将模型层与不通过中间件的命令一起使用,在这种情况下,我们应该使用先前的视图请求(因此可能与不同的用户一起使用)。如果服务器并发处理多个请求,视图也可能会看到几纳秒后到达的请求,从而再次接收错误的用户。身份验证中间件也可能是有条件的,因此并非所有请求都具有 user
属性。简而言之,有足够多的场景可能会失败,结果可能会很严重:人们看到、编辑或删除他们不“拥有”的数据(无权查看、编辑或删除)。
因此您 需要将 request
或 user
对象传递给 user_test
方法。例如:
from django.http import HttpRequest
class TestManager(models.Manager):
def user_test(self<b>, request_or_user</b>):
if isinstance(request_or_user, HttpRequest):
return self.filter(user=request_or_user.user, viewed=False)
else:
return self.filter(user=request_or_user, viewed=False)
因此必须将 request
对象从视图传递给函数。甚至这也不是真正的纯粹。真正的 pure 方法只接受 user
对象:
class TestManager(models.Manager):
def user_test(self<b>, user</b>):
return self.filter(user=user, viewed=False)
因此在一个视图中可以将其用作:
def some_view(request):
some_tests = Test.objects.user_test(request.user)
# ...
# return Http response
例如,如果我们想用这个查询集渲染一个模板,我们可以像这样传递它:
def some_view(request):
some_tests = Test.objects.user_test(request.user)
# ...
return render(request, 'my_template.html', {'some_tests': some_tests})