web-dev-qa-db-ja.com

無効なデータ。辞書が必要ですが、Django RestFrameworkのシリアライザーフィールドでstrエラーが発生しました

_Django 2.x_と_Django REST Framework_を使用しています。

私は2つのモデルがあります

_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ファイルには次のように定義されたシリアライザーがあります

_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フィールドにcontactidを渡すと

enter image description here

それはエラーを与えています

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

AmountGivenSerializerからcontact = ContactSerializer()を削除すると、期待どおりに機能しますが、depthがに設定されているため応答します1、連絡先データにはモデルフィールドのみが含まれ、他のプロパティフィールドは定義されていません。

4
Anuj TBE

私はこのリクエスト解析パターンの大ファンではありません。私の理解では、AmountGivenオブジェクトを取得するときにすべての連絡先の詳細を表示できると同時に、連絡先IDを指定するだけでAmountGivenを作成および更新できるようにする必要があります。 。

したがって、AmountGivenシリアライザーを変更して、contactモデルフィールド用に2つのフィールドを持つことができます。このような:

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()
4
slider

__init__()メソッドのAmountGivenSerializerを次のようにオーバーライドします。

_class AmountGivenSerializer(serializers.ModelSerializer):
    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()})

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


説明
問題は、定義されているため、DRFがcontactフィールドからオブジェクトのようなdictを予期することでした_nested serializer_。そこで、__init__()メソッドをオーバーライドすることで、ネストされた関係を動的に削除しました

1
JPG