Неверные данные.Ожидается словарь, но получена ошибка str с полем сериализатора в Django Rest Framework - PullRequest
0 голосов
/ 18 октября 2018

Я использую Django 2.x и Django REST Framework.

У меня есть две модели, такие как

class Contact(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.PROTECT)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100, blank=True, null=True)
    modified = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

class AmountGiven(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    contact = models.ForeignKey(Contact, on_delete=models.PROTECT)
    amount = models.FloatField(help_text='Amount given to the contact')
    given_date = models.DateField(default=timezone.now)
    created = models.DateTimeField(auto_now=True)

serializer.py в файле определены сериализаторыas

class ContactSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Contact
        fields = ('id', 'first_name', 'last_name', 'created', 'modified')

class AmountGivenSerializer(serializers.ModelSerializer):
    contact = ContactSerializer()

    class Meta:
        model = AmountGiven
        depth = 1
        fields = (
            'id', 'contact', 'amount', 'given_date', 'created'
        )

views.py

class AmountGivenViewSet(viewsets.ModelViewSet):
    serializer_class = AmountGivenSerializer

    def perform_create(self, serializer):
        save_data = {}
        contact_pk = self.request.data.get('contact', None)
        if not contact_pk:
            raise ValidationError({'contact': ['Contact is required']})
        contact = Contact.objects.filter(
            user=self.request.user,
            pk=contact_pk
        ).first()
        if not contact:
            raise ValidationError({'contact': ['Contact does not exists']})
        save_data['contact'] = contact
        serializer.save(**save_data)

Но когда я добавляю новую запись в AmountGiven модель и передаю contact idв contact поле

enter image description here

выдает ошибку как

{"contact":{"non_field_errors":["Invalid data. Expected a dictionary, but got str."]}}

Когда я удаляю contact = ContactSerializer() из AmountGivenSerializer , он работает нормально, как и ожидалось, но затем в ответ, когда depth установлен в 1, контактные данные содержат только поля модели, но не определены другие поля свойств.

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

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

Таким образом, вы можете изменить свой сериализатор AmountGiven, чтобы иметь 2 поля для поля модели contact.Например:

class AmountGivenSerializer(serializers.ModelSerializer):
    contact_detail = ContactSerializer(source='contact', read_only=True)

    class Meta:
        model = AmountGiven
        depth = 1
        fields = (
            'id', 'contact', 'contact_detail', 'amount', 'given_date', 'created'
        )

Обратите внимание, что поле contact_detail имеет атрибут source.

Теперь функциональность по умолчанию для создания и обновления должна работать «из коробки» (проверка и все).

А когда вы получаете объект AmountGiven, вы должны получить все детали дляконтакт в поле contact_detail.

Обновление

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

class AmountGivenViewSet(viewsets.ModelViewSet):
    serializer_class = AmountGivenSerializer

    def perform_create(self, serializer):
        contact = serializer.validated_data.get('contact')
        if contact.user != self.request.user:
            raise ValidationError({'contact': ['Not a valid contact']})
        serializer.save()
0 голосов
/ 18 октября 2018

Заменить __init__() метод AmountGivenSerializer как

class AmountGivenSerializer(serializers.ModelSerializer):
    <b>def __init__(self, *args, **kwargs):
        super(AmountGivenSerializer, self).__init__(*args, **kwargs)
        if 'view' in self.context and self.context['view'].action != 'create':
            self.fields.update({"contact": ContactSerializer()})</b>

    class Meta:
        model = AmountGiven
        depth = 1
        fields = (
            'id', 'contact', 'amount', 'given_date', 'created'
        )


Описание
Проблемаесли DRF ожидает объект, похожий на вихрь, из поля contact, поскольку вы определили nested serializer.Итак, я удалил вложенное отношение динамически с помощью переопределения метода __init__()

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