Получить текущего пользователя в Django, не работающего в тестах

#python #django

Вопрос:

У меня есть пара представлений в моем приложении Django, которые выполняют и действия, и записывают, кто совершил действие в БД, что-то вроде:

 def my_view(request):
    # do some stuff here first
    current_user = MyCustomUserObject.objects.filter(django_user_id=request.user.id).first()
    model_i_did_something_to_above.last_modified_by = current_user
    model.save()
 

И это на самом деле работает нормально, если я запускаю сервер и вызываю его через почтальона. Однако, когда я провожу модульный тест:

 from datetime import datetime

class MyTests(TestCase):

    def setUp(self):
        now = datetime.utcnow()
        django_user = User.objects.create_user(username='myusername',
                                           email='test@test.com',
                                           password='abcd')
        
        self.user = MyCustomUserObject(user_name='myusername', email_address='test@test.com', created_datetime=now,
                    last_modified_datetime=now, is_admin=True, django_user=django_user)
        self.user.save()
        self.tokens = json.loads(self.client.post(reverse('authenticate'),
                                                  data={'username': 'myusername',
                                                        'password': 'abcd'},
                                                  content_type='application/json').content)

    def test_stuff(self):
        self.client.delete(reverse('nameoftheurl'),
                               {data: 'stuff'},
                               content_type='application/json',
                               **{'HTTP_AUTHORIZATION': self.tokens['access']})
 

И это доходит до взгляда, он говорит, что request.user.id это Не Так. Почему это происходит? Есть ли способ обойти это?

Редактировать

Представление проверки подлинности выглядит следующим образом:

 from rest_framework_simplejwt.views import TokenObtainPairView

urlpatterns = [
    path('authenticate/', TokenObtainPairView.as_view(), name='authenticate'),
    ]
 

Я также обновил приведенный выше тестовый пример, чтобы показать, как создается пользователь.

Комментарии:

1. Можете ли вы поделиться тем, как выглядит представление аутентификации? И как вы создали пользователя перед аутентификацией в тестах?

2. @bdbd пожалуйста, посмотрите мою правку, чтобы ответить на эти вопросы!

3. @rodrigocf Вы можете попробовать добавить self.user.refresh_from_db() сразу после self.user.save() в функции настройки в модульном тесте.

4. Пожалуйста, добавьте код (может быть промежуточным программным обеспечением), который отвечает за настройку request.user из HTTP_AUTHORIZATION заголовка.

Ответ №1:

Проблема, по-видимому, заключается в том, что в заголовке авторизации отсутствует тип авторизации в test_stuff тестовом случае.

Это должно быть:

 headers={'Authorization': f"Bearer {self.tokens['access']}"}
 

Так:

     def test_stuff(self):
        self.client.delete(reverse('nameoftheurl'),
                               {data: 'stuff'},
                               content_type='application/json',
                               **{'HTTP_AUTHORIZATION': f"Bearer {self.tokens['access']}")
                                                       #  ^^^ Add this
 

Комментарии:

1. Вот оно. Я не могу поверить, что все было так просто. Поскольку срок действия награды истек, я начал ее снова и начислю очки завтра вечером. Спасатель жизни, по-крупному. @bdbd

Ответ №2:

Вы забыли войти в систему своего пользователя:

 class MyTests(TestCase):

    ...

    def test_stuff(self):
        self.client.force_login(self.user)
        self.client.delete(
            reverse('nameoftheurl'),
            {data: 'stuff'},
            content_type='application/json',
            HTTP_AUTHORIZATION=self.tokens['access'],
        )
 

Отрывок из authentication docs :

Если текущий пользователь не вошел в систему, этот атрибут будет установлен как экземпляр пользователя-анонима, в противном случае это будет экземпляр Пользователя.

AnonymousUser У него id установлено значение None , следовательно, ваша ошибка.

Обратите внимание, что это также указывает на ошибку в вашем представлении удаления. Вы должны проверить, что пользователь вошел в систему, прежде чем пытаться выйти из нее, в противном случае в какой-то момент (если еще нет) вы вернете ошибку 500.