DRF, разрешения и тесты: получение 403 запущенных тестов, 200 OK в браузере - PullRequest
0 голосов
/ 07 ноября 2019

Я продолжаю свой путь тестирования моего приложения Django Rest Framework, так как я добавляю новые представления и дополнительные функциональные возможности. Я должен признать, что на данном этапе я считаю, что тестирование сложнее, чем собственно кодирование и сборка моего приложения. Я чувствую, что ресурсов для тестирования DRF гораздо меньше, чем ресурсов, рассказывающих о создании инфраструктуры REST с DRF. C'est la vie, однако, я воюю.

Моя проблема, с которой я сейчас сталкиваюсь, заключается в том, что я получаю ошибку 403 при тестировании одного из моих DRF ViewSets. Я могу подтвердить, что представление и его разрешения работают нормально при использовании браузера или обычного сценария Python для доступа к конечной точке.

Давайте начнем с модели, которая используется в моем ViewSet

class QuizTracking(models.Model):
    case_attempt = models.ForeignKey(CaseAttempt, on_delete=models.CASCADE)
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    answer = models.ForeignKey(Answer, on_delete=models.CASCADE)
    timestamp = models.DateTimeField(auto_now_add=True)

Следует отметить, что для пользователя существует FK. Это используется при определении разрешений.

Вот моя тестовая функция. Для краткости я не включил код для всего класса.

    def test_question_retrieve(self):
        """
            Check that quiz tracking/ID returns a 200 OK and the content is correct
        """
        jim = User(username='jimmy', password='monkey123', email='jimmy@jim.com')
        jim.save()
        quiz_tracking = QuizTracking(answer=self.answer, case_attempt=self.case_attempt, user=jim)
        quiz_tracking.save()
        request = self.factory.get(f'/api/v1/progress/quiz-tracking/{quiz_tracking.id}')

        # How do I refernce my custom permission using Permission.objects.get() ?
        # permission = Permission.objects.get()
        # jim.user_permissions.add(permission)

        self.test_user.refresh_from_db()
        force_authenticate(request, user=jim)
        response = self.quiz_detail_view(request, pk=quiz_tracking.id)
        print(response.data)
        print(jim.id)
        print(quiz_tracking.user.id)

        self.assertContains(response, 'answer')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

В приведенном выше коде я определяю пользователя jim и quiz_tracking объект, принадлежащий jim.

Я создаю свой запрос, force_authenticate запрос и выполняю мой запрос, и сохраняю ответ в response.

. Интересно отметить следующее: - jim.id и quiz_tracking. user.id имеют то же значение - я получаю ответ 403 с

{'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}

Возможно, вы заметили, что я прокомментировал permission = Permission.objects.get() Насколько я понимаю, мне нужно пройти этот класс разрешений, который вмой случай IsUser. Однако в моей БД нет записи об этом, и, следовательно, Permission.objects.get('IsUSer') вызов не выполняется.

Итак, у меня следующие вопросы: - Как мне подтвердить свой запрос, чтобы я получил 200 OK? - Нужно ли мне добавлять разрешение моему пользователю в моих тестах, и если да, то какое разрешение и с каким синтаксисом?

Ниже мое представление, а ниже мой файл пользовательских разрешений, определяющий IsUser

class QuickTrackingViewSet(viewsets.ModelViewSet):
    serializer_class = QuizTrackingSerializser

    def get_queryset(self):
        return QuizTracking.objects.all().filter(user=self.request.user)

    def get_permissions(self):
        if self.action == 'list':
            self.permission_classes = [IsUser, ]
        elif self.action == 'retrieve':
            self.permission_classes = [IsUser, ]

        return super(self.__class__, self).get_permissions()

NB Если я закомментирую def get_permissions(), тогда мой тест пройдет без проблем.

Мой пользовательский permission.py

from rest_framework.permissions import BasePermission


class IsSuperUser(BasePermission):

    def has_permission(self, request, view):
        return request.user and request.user.is_superuser


class IsUser(BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.user:
            if request.user.is_superuser:
                return True
            else:
                return obj == request.user
        else:
            return False

Приветствия

С

1 Ответ

1 голос
/ 07 ноября 2019

Кажется, что проблема в вашем разрешении IsUser.

Вы сравниваете QuizTracking экземпляр с пользовательским экземпляром.

измените эту строку

return obj == request.user

на

return obj.user.id == request.user.id

Одно предложение вне темы

Вы можете написать свой класс IsUser следующим образом, который легче читать

class IsUser(BasePermission):

    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated

    def has_object_permission(self, request, view, obj):
        return request.user.is_superuser or obj.user.id == request.user.id

Обратите внимание, что has_object_permission вызывается только в том случае, если уровень просмотра has_permission возвращает значение True.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...