无效数据。需要一个字典,但 Django Rest Framework 中的序列化程序字段出现 str 错误
Invalid data. Expected a dictionary, but got str error with serializer field in Django Rest Framework
我正在使用 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 文件的序列化器定义为
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
字段中传递 contact
id 时
它给出的错误是
{"contact":{"non_field_errors":["Invalid data. Expected a dictionary, but got str."]}}
当我从 AmountGivenSerializer 中删除 contact = ContactSerializer()
时,它按预期工作正常,但随后响应 depth
设置为 1,联系人数据包含仅模型字段,未定义其他 属性 字段。
覆盖AmountGivenSerializer
的__init__()
方法为
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__()
方法
动态删除了 嵌套关系
我不太喜欢这种请求解析模式。据我了解,您希望在检索 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
是否属于某个用户(但是,我在您的 Contact
模型上没有看到 user
字段,也许您错过了发布它)。您可以简化该检查:
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()
我正在使用 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 文件的序列化器定义为
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
字段中传递 contact
id 时
它给出的错误是
{"contact":{"non_field_errors":["Invalid data. Expected a dictionary, but got str."]}}
当我从 AmountGivenSerializer 中删除 contact = ContactSerializer()
时,它按预期工作正常,但随后响应 depth
设置为 1,联系人数据包含仅模型字段,未定义其他 属性 字段。
覆盖AmountGivenSerializer
的__init__()
方法为
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__()
方法
我不太喜欢这种请求解析模式。据我了解,您希望在检索 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
是否属于某个用户(但是,我在您的 Contact
模型上没有看到 user
字段,也许您错过了发布它)。您可以简化该检查:
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()