Почему тест django-rest-framework возвращает другой ответ, чем идентичное сообщение через postman?

Контекст:

В настоящее время я переписываю свою реализацию django-rest-framework для использования пользовательского класса разрешений. В процессе я пишу тесты, чтобы убедиться, что любые будущие изменения ничего не сломают.

Связанные объекты:

View

Serializer

Симптомы:

Я выполняю следующий тест:

def test_event_edit_authenticated_non_org_user(self):
        '''test that an event can be edited by an non-org user'''
        #self.client.force_authenticate(user=self.user1)
        response = self.client.post(
            '/backend/api/event/',
            {
                'name': 'Test Event',
                'content': 'This is a test event',
                'start': '2020-01-01T00:00:00Z',
                'end': '2020-01-01T01:00:00Z',
                'organizationChange': self.org1.short_name,
                'location': 'Test Location',
            },
            HTTP_AUTHORIZATION='Token ' + self.token1.key,
            format='json'
        )
        self.assertEqual(response.status_code, 201)
        event = Event.objects.get(uuid=response.data['uuid'])
        #self.client.force_authenticate(user=self.user2)
        response = self.client.patch(
            '/backend/api/event/' + str(event.uuid) + '/',
            {'uuid': str(event.uuid),
             'name': 'Test Event 2',
             'content': 'This is a test event',
             'start': '2020-01-01T00:00:00Z',
             'end': '2020-01-01T01:00:00Z',
             'location': 'Test Location',
            },
            HTTP_AUTHORIZATION='Token ' + self.token2.key,
            format='json'
        )
        self.assertEqual(response.status_code, 403)

Я получаю эту ошибку:

======================================================================
ERROR: test_event_edit_authenticated_non_org_user (events.tests.EventTest.test_event_edit_authenticated_non_org_user)
test that an event can be edited by an non-org user
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\env\scorg\django\events\tests.py", line 232, in test_event_edit_authenticated_non_org_user
    event = Event.objects.get(uuid=response.data['uuid'])
                                   ~~~~~~~~~~~~~^^^^^^^^
KeyError: 'uuid'

У меня аналогичная ошибка во всех моих тестах, которые требуют uuid как часть данных ответа.

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

1. Я проверил, что поле 'uuid' не возвращается, распечатав ответ.

Response for event creation: {'name': 'Test Event', 'source': None, 'discord_event_id': None, 'my_interest': False, 'organization': None, 'content': 'This is a test event', 'start': '2020-01-01T00:00:00Z', 'end': '2020-01-01T01:00:00Z', 'location': 'Test Location', 'discord_link': None, 'discord_description': None, 'discord_location': None, 'interested': None, 'jobs': None, 'canRead': True, 'canWrite': False, 'canEdit': False, 'canDelete': False}

Это подтвердило, что поле uuid не возвращается.

2. Я проверил, что 'uuid' включен в соответствующий сериализатор:

lass EventSerializer(serializers.ModelSerializer):
    ...

    class Meta:
        model = Event
        fields = ['uuid','name','source','discord_event_id','my_interest','organization','short_name','content','owner','type','start','end','location','discord_link','discord_event_id','discord_description','discord_location','status','created','interested','jobs','canRead','canWrite','canEdit','canDelete']

    ...

Это подтвердило, что поле 'uuid' включено в соответствующий сериализатор.

3. Я создал ручную почту с помощью Postman, чтобы проверить, имеет ли ручная почта такую же проблему.

POST запрос:

{
    "name": "Test Event2",
    "content": "This is a test event",
    "start": "2020-01-01T00:00:00Z",
    "end": "2020-01-01T01:00:00Z",
    "organizationChange": "ESHORES",
    "location": "Test Location"
}

Ответ:

{
    "uuid": "7f7568b0-a07c-441d-915d-9ab3d3619a01",
    "name": "Test Event2",
    "source": "scorg",
    "discord_event_id": null,
    "my_interest": false,
    "organization": {
        "uuid": "6fcec5b4-b2b4-49ea-bcb4-93ff585670e4",
        "name": "ESHORES",
        "short_name": "ESHORES",
        "url": "https://robertsspaceindustries.com/orgs/ESHORES/"
    },
    "short_name": "ESHORES",
    "content": "This is a test event",
    "owner": 231574499013820417,
    "type": 0,
    "start": "2020-01-01T00:00:00Z",
    "end": "2020-01-01T01:00:00Z",
    "location": "Test Location",
    "discord_link": null,
    "discord_description": null,
    "discord_location": null,
    "status": 0,
    "created": "2023-01-11T20:07:02.783395Z",
    "interested": null,
    "jobs": [],
    "canRead": true,
    "canWrite": true,
    "canEdit": true,
    "canDelete": true
}

Очевидно, что он правильно возвращает uuid.

4. Я искал в google/stack/reddit и даже спрашивал chatGPT безрезультатно.

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

Поскольку вы вручную вставляете 'uuid' в validated_data, он не будет находиться в response.data. Если вы хотите подтвердить фактический возвращаемый вывод, вам нужно проверить необработанный response.content:

data = json.loads(response.content)
uuid = data['uuid']

Это фактическое тело ответа, которое было возвращено из конечной точки.

def test_event_edit_authenticated_non_org_user(self):
        '''test that an event can be edited by an non-org user'''
        #self.client.force_authenticate(user=self.user1)
        response = self.client.post(
            '/backend/api/event/',
            { 
                'uuid': '79576b8d-2225-42a7-be58-9b61033cbea7',
                'name': 'Test Event',
                'content': 'This is a test event',
                'start': '2020-01-01T00:00:00Z',
                'end': '2020-01-01T01:00:00Z',
                'organizationChange': self.org1.short_name,
                'location': 'Test Location',
            },
            HTTP_AUTHORIZATION='Token ' + self.token1.key,
            format='json'
        )
        self.assertEqual(response.status_code, 201)
        event = Event.objects.last()

Вам придется указать UUID вручную Теперь вы будете использовать переменную события для получения всех полей модели событий

Пройдя через логику, я обнаружил, что в проверке разрешений была допущена ошибка. Я делал это слишком рано и не включил параметр. Я не могу объяснить, почему это работало на postman, но не на моих тестах, но изменение следующих параметров устранило ошибку:

def perform_create(self, serializer):
        user = self.request.user
        org = None
        # check if user has necessary permissions to create events
        if 'organizationChange' in self.request.data:
            try:
                org = Organization.objects.get(short_name=self.request.data['organizationChange'])
            except:
                print('Organization does not exist')
                pass
        elif 'guild' in self.request.data:
            try:
                org = DiscordServer.objects.get(server_id=self.context['request'].data['guild']).org
            except:
                pass
        perm = CheckPermission(capability='event', org=org, action='create').has_permission(self.request, self)

Я переместил perm = CheckPermission() с верхнего уровня логики 'if organizationChange' на нижний, и это решило проблему. uuid не передавался, потому что объект не был успешно создан.

Вернуться на верх