And*_*rew 4 python django django-rest-framework
我创建了一个嵌套序列化器,当我尝试在其中发布数据时,它会继续显示外键值不能为空或需要字典。我已经经历了各种类似的问题并尝试了答案,但它对我不起作用。这是模型
##CLasses
class Classes(models.Model):
class_name = models.CharField(max_length=255)
class_code = models.CharField(max_length=255)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.class_name
class Meta:
ordering = ['class_code']
##Streams
class Stream(models.Model):
stream_name = models.CharField(max_length=255)
classes = models.ForeignKey(Classes,related_name="classes",on_delete=models.CASCADE)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.stream_name
class Meta:
ordering = ['stream_name']
Run Code Online (Sandbox Code Playgroud)
这是视图
class StreamViewset(viewsets.ModelViewSet):
queryset = Stream.objects.all()
serializer_class = StreamSerializer
Run Code Online (Sandbox Code Playgroud)
这是序列化器类
class StreamSerializer(serializers.ModelSerializer):
# classesDetails = serializers.SerializerMethodField()
classes = ClassSerializer()
class Meta:
model = Stream
fields = '__all__'
def create(self,validated_data):
classes = Classes.objects.get(id=validated_data["classes"])
return Stream.objects.create(**validated_data, classes=classes)
# def perfom_create(self,serializer):
# serializer.save(classes=self.request.classes)
#depth = 1
# def get_classesDetails(self, obj):
# clas = Classes.objects.get(id=obj.classes)
# classesDetails = ClassSerializer(clas).data
# return classesDetails
Run Code Online (Sandbox Code Playgroud)
我尝试了多种启用创建方法的方法,但像这样显示错误{"classes":{"non_field_errors":["Invalid data. Expected a dictionary, but got int."]}}。任何贡献将不胜感激
这是使用 DRF 开发 API 时非常常见的情况。
在 DRF 到达该create()方法之前,它会验证输入,我认为其形式类似于
{
"classes": 3,
"stream_name": "example"
}
Run Code Online (Sandbox Code Playgroud)
这意味着,既然指定了
{
"classes": 3,
"stream_name": "example"
}
Run Code Online (Sandbox Code Playgroud)
classesDRF 正在尝试从整数构建字典。当然,这样会失败,从错误字典中可以看到
classes = ClassSerializer()
Run Code Online (Sandbox Code Playgroud)
{field_name}_id)read_only=True一个可能的解决方案是在您的 中设置ClassSerializer,并在编写时使用该字段的替代名称,这很常见{field_name}_id。这样,验证就不会完成。有关更多详细信息,请参阅此答案。
{"classes":{"non_field_errors":["Invalid data. Expected a dictionary, but got int."]}}
Run Code Online (Sandbox Code Playgroud)
这是一个干净的解决方案,但需要更改用户 API。如果这不是一个选项,请继续执行下一个解决方案。
to_internal_value)这里我们重写该to_internal_value方法。这是嵌套ClassSerializer抛出错误的地方。为了避免这种情况,我们将该字段设置为read_only并管理方法中的验证和解析。
请注意,由于我们没有classes在可写表示中声明字段,因此默认操作super().to_internal_value是忽略字典中的值。
class StreamSerializer(serializers.ModelSerializer):
classes = ClassSerializer(read_only=True)
class Meta:
model = Stream
fields = (
'pk',
'stream_name',
'classes',
'created_date',
'classes_id',
)
extra_kwargs = {
'classes_id': {'source': 'classes', 'write_only': True},
}
Run Code Online (Sandbox Code Playgroud)
通过这个解决方案,您可以使用相同的字段名称进行读取和写入,但代码有点混乱。
related_name错误地使用了该参数,请参阅此问题。恰恰相反,from rest_framework.exceptions import ValidationError
class StreamSerializer(serializers.ModelSerializer):
classes = ClassSerializer(read_only=True)
def to_internal_value(self, data):
classes_pk = data.get('classes')
internal_data = super().to_internal_value(data)
try:
classes = Classes.objects.get(pk=classes_pk)
except Classes.DoesNotExist:
raise ValidationError(
{'classes': ['Invalid classes primary key']},
code='invalid',
)
internal_data['classes'] = classes
return internal_data
class Meta:
model = Stream
fields = (
'pk',
'stream_name',
'classes',
'created_date',
)
Run Code Online (Sandbox Code Playgroud)
在这种情况下应该是streams。
| 归档时间: |
|
| 查看次数: |
3803 次 |
| 最近记录: |