7

我正在尝试做的事情:

我正在尝试访问我的 django 模型中的请求对象,以便我可以使用request.user.

我试过的:

我在这个网站上发现了一个黑客。但是评论中有人指出在生产时不要这样做。

__init__就像这篇文章中提到的那样,我还尝试覆盖模型的方法。但我得到了一个AttributeError: 'RelatedManager' object has no attribute 'request'

模型.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()
4

1 回答 1

11

我试图访问我的 Django 模型中的请求对象,以便我可以使用request.user.

一个问题是模型本身并没有在请求的上下文中使用。例如,一种经常定义自定义命令来记账,或者一种可以定义一个 API,例如用户存在的地方。Django 方法的想法是模型不应该请求感知的。模型定义“业务逻辑”层:模型定义实体以及它们如何交互。如果不尊重这些层,就会使应用程序容易出现很多问题。

您引用的博客旨在创建他们所谓的全局状态(这是一种严重的反模式):当视图进行调用时,您将请求保存在中间件中,这样您就可以在模型层中获取该对象. 这种方法存在一些问题:首先,正如已经说过的,并非所有用例都是视图,因此并非所有用例都通过中间件。因此,在获取该属性时可能存在该属性。

此外,不能保证请求对象确实是视图的请求对象。例如,我们可能将模型层与不通过中间件的命令一起使用,在这种情况下,我们应该使用先前的视图请求(因此可能与不同的用户一起使用)。如果服务器同时处理多个请求,视图也可能会看到几纳秒后到达的请求,从而再次获取错误的用户。身份验证中间件也可能是有条件的,因此并非所有请求都具有user属性。简而言之,有足够多的场景可能会失败,并且结果可能很严重:人们查看、编辑或删除他们不“拥有”的数据(无权查看、编辑或删除)。

因此,您需要将request、 或user对象传递给该user_test方法。例如:

from django.http import HttpRequest

class TestManager(models.Manager):
    def user_test(self, request_or_user):
        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对象从视图传递给函数。甚至这也不是很纯粹。真正的纯粹方法只会接受一个user对象:

class TestManager(models.Manager):
    def user_test(self, user):
            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})
于 2018-09-07T10:15:16.863 回答