Validated_data возвращает пустой OrderedDict для вложенных полей с Django Rest Framework

Может ли кто-нибудь помочь мне выяснить, почему некоторые поля не парсятся правильно при использовании вложенных серийников с Django и Django-rest-framework?

Я исследовал проблему на SO, и единственная причина, по которой это происходит, которую я нашел, это то, что запрос отправляется как Form-data, а не Json, но я проверил, что response.content_type равен application/json - так что это не должно быть проблемой здесь.

Вот как выглядят мои проверенные данные (обратите внимание, что 3 из полей содержат только пустой OrderedDict):

{'author': OrderedDict(),
 'disclosed_at': datetime.datetime(2021, 10, 19, 12, 0, tzinfo=<DstTzInfo 'Europe/Stockholm' CEST+2:00:00 DST>),
 'event_date': datetime.date(2021, 10, 20),
 'event_type': OrderedDict(),
 'subject_companies': [OrderedDict()]}

Вот как выглядит request.data (где видно, что все поля присутствуют, а поля, которые указал каждый сериализатор, представлены ниже этого абзаца):

{'event_type': {'pk': 1}, 'author': {'pk': 1}, 'event_date': '2021-10-20', 'disclosed_at': '2021-10-19 12:00:00', 'subject_companies': [{'pk': 1}]}

Вот откуда я отправляю запрос (test.py):

  def test_authenticated_creating_event_for_own_organisation(self):
        view = NewsEventList.as_view()
        url = reverse('news_event_list', kwargs={'pk': self.organisation.pk})
        request = self.client.post(url, data=json.dumps(self.payload_event), content_type='application/json')
        force_authenticate(request, user=self.user)
        response = view(request, pk=self.organisation.pk)
        
        json_data = json.dumps(response.data, indent=4)
        json_ = (json.loads(json_data))  

        self.assertEqual(response.status_code, 201, 'Should return 201 - Created')
        return response

Вид

class NewsEventList(generics.ListCreateAPIView):
permission_classes = (IsAuthenticatedAndOfSameOrganisationEvents,)
serializer_class = NewsEventSerializer

def get_queryset(self):
    org_pk = self.kwargs.get('pk', None)
    try:
        org_obj = Organisation.objects.get(pk=org_pk)
    except Organisation.DoesNotExist:
        return ValidationError('Organisation does not exist')

    news_events = NewsEvent.objects.filter(author=org_obj)
    return news_events

Serializers

class OrganisationNameSerializer(ModelSerializer):

    class Meta:
        model = Organisation
        fields = ['pk']


class EventTypeSerializer(ModelSerializer):

    class Meta:
        model = EventType
        fields = ['pk']

class HeadlineSerializer(ModelSerializer):

    class Meta:
        model = EventHeadline
        fields = ['news_event', 'language', 'headline']

class NewsEventSerializer(ModelSerializer):
    event_type = EventTypeSerializer()
    author = OrganisationNameSerializer()
    subject_companies = OrganisationNameSerializer(many=True)

    class Meta:
        model = NewsEvent
        fields = ['pk', 'event_type', 'author', 'event_date', 'event_time', 'disclosed_at', 'subject_companies', 'created_at', 'updated_at']

    def create(self, validated_data):

        # Get PK for organisation from URL
        org_pk = self.context.get('request').parser_context.get('kwargs', {}).get('pk', {})
        org_obj = Organisation.objects.get(pk=org_pk)

        print(self.context.get('request').data)
        pprint(validated_data)

Также для справки я распечатал serializer.data для уже существующего экземпляра NewsEvent:

news_event_test = NewsEvent.objects.all()[0]
serializer = NewsEventSerializer(news_event_test)
print(serializer.data)
    
{'pk': 1, 'event_type': OrderedDict([('pk', 1)]), 'author': OrderedDict([('pk', 1)]), 'event_date': None, 'event_time': None, 'disclosed_at': None, 'subject_companies': [OrderedDict([('pk', 1)])], 'created_at': '2021-10-25T09:32:41.562428+02:00', 'updated_at': '2021-10-25T09:32:41.562487+02:00'}

Я также пробовал делать "pop" каждого поля из validated_object, но только те, которые не являются пустым OrderedDict работают, например, disclosed_at, но если я пытаюсь сделать:

event_type = validated_data.pop('event_type')

Я получаю:

KeyError: "Got KeyError when attempting to get a value for field `event_type` on serializer `NewsEventSerializer`.\nThe serializer field might be named incorrectly and not match any attribute or key on the `dict` instance.\nOriginal exception text was: 'event_type'."
event_type = models.ForeignKey('publication.EventType', on_delete=models.SET_NULL, related_name='events_type', null=True)
author = models.ForeignKey('core.Organisation', on_delete=models.CASCADE, related_name='events_author', null=True)
subject_companies = models.ManyToManyField('core.Organisation',  related_name='events_companies')

Замените эти строки, удалите предыдущие миграции и создайте новые и попробуйте.

Причина в том, что я выполнял операцию записи (POST запрос, действие create в терминах Django/DRF), а поле pk в сериализаторах по умолчанию доступно только для чтения

Чтобы проверить эти данные во время операций записи, вам нужно явно задать поле и установить read_only=False.

Это решило проблему, но вы можете рассмотреть возможность использования PrimaryKeyRelatedField, если ваш случай использования заключается только в установке первичного ключа связанного объекта.

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