validated_data возвращает пустой упорядоченный индекс для вложенных полей с помощью платформы Django Rest

#django #django-rest-framework

Вопрос:

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

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

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

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

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

 {'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 NewsEvent(TimeStampedModel):  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')    legacy_id = models.CharField(max_length=128, blank=True)  event_date = models.DateField(null=True, blank=True)  event_time = models.TimeField(null=True, blank=True)  disclosed_at = models.DateTimeField(null=True, blank=True)  created_at = models.DateTimeField(auto_now_add=True)  updated_at = models.DateTimeField(auto_now=True)    def __str__(self):  return '{}: {}'.format(self.author, self.event_type)    class Meta:  ordering = ('pk',)   class EventType(models.Model):  language = models.ForeignKey(  'core.Language',   default=get_default_language,   null=True,   on_delete=models.SET_NULL,  related_name='event_contents'  )  name = models.CharField(max_length=64, default=None)  key = models.CharField(max_length=64, default=None)   def __str__(self):  return '{}'.format(self.name)    class Meta:  ordering = ('pk',)  

The view

 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)  

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

 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'}  

Я также пытался выполнить «всплывающее окно» каждого из полей из validated_object, но только те, которые этого не делают, являются пустой упорядоченной работой, такой как 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'."  

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

1. можете ли вы добавить фрагмент кода вашего представления?

2. Я добавил представление @Shaonsani

3. Также добавьте модели !

4. Добавлены модели @Shaonsani

5. просто попробуйте мой ответ и дайте мне знать

Ответ №1:

 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')  

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

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

1. Не видите, что вы внесли какие-то коррективы?

Ответ №2:

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

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

 class RedditTestSerializer(serializers.ModelSerializer):  class Meta:  model = models.Task  fields = ("pk",)  

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