Как безопасно получить доступ к объекту запроса в моделях Django - PullRequest
0 голосов
/ 07 сентября 2018

Что я пытаюсь сделать:

Я пытаюсь получить доступ к объекту запроса в моих моделях django, чтобы я мог получить зарегистрированного пользователя с помощью request.user.

Что я пробовал:

Я нашел взлом на этом сайте. Но кто-то в комментариях указал, чтобы не делать это, когда в производстве.

Я также пытался переопределить метод __init__ модели, как упоминалось в этом посте. Но я получил 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()

1 Ответ

0 голосов
/ 07 сентября 2018

Я пытаюсь получить доступ к объекту запроса в моих моделях Django, чтобы я мог получить пользователя, вошедшего в систему в данный момент, с помощью request.user.

Что ж, проблема в том, что модели не сами по себе используются в контексте запроса. Например, один часто определяет пользовательских команд для ведения бухгалтерии, или один может определять API, где, например, пользователь не присутствует. Идея подхода Django состоит в том, что модели должны , а не учитывать запросы . Модели определяют слой «бизнес-логики»: модели определяют сущности и то, как они взаимодействуют. Не соблюдая эти уровни, можно сделать приложение уязвимым для множества проблем.

Блог, на который вы ссылаетесь, нацелен на создание того, что они называют глобальным состоянием (что является серьезным антипаттеном ): вы сохраняете запрос в промежуточном ПО, когда представление делает вызов, так что вы можете получить этот объект на уровне модели. У этого подхода есть некоторые проблемы: во-первых, как уже говорилось, не все варианты использования являются представлениями, и, следовательно, не все варианты использования проходят через промежуточное ПО. Таким образом, возможно, что атрибут не существует при его извлечении.

Кроме того, не гарантируется, что объект запроса действительно является объектом запроса представления. Например, возможно, что мы используем уровень модели с командой, которая, таким образом, не проходит через промежуточное программное обеспечение, и в этом случае мы должны использовать предыдущий запрос представления (таким образом, потенциально с другим пользователем). Если сервер обрабатывает несколько запросов одновременно, также возможно, что представление увидит запрос, поступивший через несколько наносекунд, и, таким образом, снова примет не того пользователя. Также возможно, что промежуточное ПО аутентификации является условным и, следовательно, не все запросы имеют атрибут 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})
...