首页 > 解决方案 > 编写 django rest 序列化程序的问题

问题描述

我正在尝试编写一个 Django Rest Framework 序列化程序。它应该接受一个简单的原始数据并返回一些相关对象数据的数据。我要序列化的模型是 Model_C

以下是模型:

class ModelA(models.Model):
    name = models.Charfield(max_length=16)
    attr1 = models...
    ...

class ModelB(models.Model):
    name = models.CharField(max_length=16)
    attr1 = models...
    ...

class ModelC(models.Model):
    model_a = models.ForeignKey(ModelA)
    model_b = models.ForeignKey(ModelB)
    text = models.CharField(max_length=32)
    date = models.DateTimeField()

这是api视图:

class ModelCApiView(RetrieveUpdateDestroyAPIView):
    serializer_class = ModelCSerializer

    def get_queryset(self):
        return self.serializer_class.Meta.model.objects.all()

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

提供给序列化器的数据如下(有或没有 ID):

{'id': '1', 'model_a': 1, 'model_b': 1, 'text': 'some text', 'date': '2019-08-28 08:00:00'}

现在,问题是序列化程序应该保存实例并返回带有一些相关数据的序列化模型:

{'id': '1', 'model_a': {'id': 1, 'name': 'some model a name'}, 'model_b': {'id': 1, 'name': 'some model b name', 'attr1': 'some attr value'}, 'text': 'some text', 'date': '2019-08-28 08:00:00'}

因此,唯一创建的是 ModelC 实例。api 视图不应该创建 ModelA 或 ModelB 实例。

主要问题是序列化/反序列化对象。我已经尝试了几件事:

  1. 最简单的
class ModelCSerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelC
        fields = "__all__"

它正确地反序列化请求,保存实例,但返回的信息太少 - 只有相关对象的 ID。


  1. 我用了深度
class ModelCSerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelC
        fields = "__all__"
        depth = 1

这不起作用,因为它吐出 500 错误:“列'model_a_id'不能为空”。


  1. 我尝试添加到 2. 声明的序列化程序:
class ModelCSerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelC
        fields = "__all__"
        depth = 1
    model_a = ModelASerializer()
    model_b = ModelBSerializer()

这会产生错误 400,错误请求,因为它要求我将 model_a 和 model_b 的所有数据作为字典插入。


  1. 我向 APIView 添加了行以使用简单的序列化程序序列化数据,然后使用更高级的再次序列化并返回更多信息。
    serializer = ModelCSerializer

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            obj = serializer.save()
            serializer = ModelCReadOnlySerializer(instance=obj, data=serializer.data)
            serializer.is_valid()
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class ModelCReadOnlySerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelC
        fields = ("id", "model_a", "model_b", "text", "date")
        read_only_fields = fields
        depth = 1

这是最接近我一直以来的解决方案,因为它返回几乎我需要的东西,除了它返回 model_a 和 model_b 的所有数据,这太多了。


在这一点上,我还有其他想法,但我敢打赌它们都很糟糕。我很高兴有任何提示如何继续,因为我已经很接近了-> || <- 在没有 DRF 的情况下自己编写所有内容 :-)

先感谢您。

标签: pythondjangoserializationdjango-rest-framework

解决方案


在@dirkgroten 的大力帮助下:

第四条是要走的路。首先,必须有两个序列化器:一个用于写入(根据 1.),一个用于读取:

class ModelCReadOnlySerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelC
        fields = ("id", "model_a", "model_b", "text", "date")
        read_only_fields = fields
    # Not there is no depth any more
    model_a = ModelASerializer()
    model_b = ModelBSerializer()

并且在视图中,数据不需要传入只读序列化器:

if serializer.is_valid():
            obj = serializer.save()
            serializer = ModelCReadOnlySerializer(instance=obj)
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

现在以简单的形式接收数据,处理并保存,然后返回更多详细信息。

再次感谢!


推荐阅读