代码之家  ›  专栏  ›  技术社区  ›  l0b0

如何在序列化Django模型时包含父对象?

  •  0
  • l0b0  · 技术社区  · 6 年前

    class Foo(models.Model):
        code = models.CharField(max_length=255)
    
    
    class Bar(models.Model):
        foo = models.ForeignKey(Foo)
        description = models.CharField(max_length=255)
    

    电流 rest_framework -基于序列化程序如下所示:

    class FooSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Foo
            fields = ('id', 'code')
    
    
    class BarSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Bar
            fields = ('id', 'foo', 'description')
    

    所以一个GET请求 Bar 将返回如下内容:

    {
        "id": 1,
        "foo": 2,
        "description": "[…]"
    }
    

    BarSerializer 而是返回全部 Foo 对象, 这样地:

    {
        "id": 1,
        "foo": {
            "id": 2,
            "code": "[…]"
        },
        "description": "[…]"
    }
    

    ?

    请记住,我仍然需要能够创建一个 酒吧 只提供 description 我试过各种方法,包括指定 foo = FooSerializer() 条形码序列化程序 酒吧 和以前一样,它抱怨我没有提供 code

    2 回复  |  直到 6 年前
        1
  •  1
  •   JPG    6 年前

    简单优雅的解决方案

    to_represention() 方法as,

    class BarSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Bar
            fields = ('id', 'foo', 'description')
    
        def to_representation(self, instance):
            data = super().to_representation(instance)
            data['foo'] = FooSerializer(instance.foo).data
            return data




    原始版本

    depth=1 在里面 BarSerializer

    
    class BarSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Bar
            fields = ('id', 'foo', 'description')
            depth = 1


    参考文献
    depth [DRF-Doc]

    更新-1
    两个不同的序列化程序

    
    class BarWriteSerializer(serializers.ModelSerializer):
        class Meta:
            model = Bar
            fields = ('id', 'foo', 'description')
    
        def to_representation(self, instance):
            data = super().to_representation(instance)
            data['foo'] = FooSerializer(instance.foo).data
            return data
    
    
    class BarReadSerializer(serializers.ModelSerializer):
        class Meta:
            model = Bar
            fields = ('id', 'foo', 'description')
            depth = 1
    

    在您看来,覆盖 get_serializer_class()

    from rest_framework import viewsets
    
    
    class SampleViewset(viewsets.ModelViewSet):
        queryset = Bar.objects.all()
    
        def get_serializer_class(self):
            if self.action == 'create':
                return BarWriteSerializer
            return BarReadSerializer

    使用的有效负载 Bar

    {
        "foo":1,# The "pk" of "Foo" instance
        "description":"bar description"
    }
    
        2
  •  0
  •   Sachin    6 年前

    解决方案

    class FooSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Foo
            fields = ('id', 'code')
    
    
    class BarSerializer(serializers.ModelSerializer):
        foo = FooSerializer(models.Foo.objects.all(), read_only=True)
        foo_id = serializers.PrimaryKeyRelatedField(
            source='foo',
            queryset=models.Foo.objects.all(),
            write_only=True
        )
    
        class Meta:
            model = models.Bar
            fields = ('id', 'foo', 'foo_id', 'description')
    

    将嵌套序列化程序用作 read_only 为了得到全部 Foo 对象。
    write_only 领域 foo_id

    现在,您的请求数据将如下所示:

    { 'foo_id': 1, 'description': 'foo bar' }

    或者,如果不需要两个字段,一个用于读取,另一个用于写入,则可以重写 create / update 方法来捕获 foo

    例子

    class BarSerializer(serializers.ModelSerializer):
        foo = FooSerializer(Foo.objects.all())
    
        class Meta:
            model = models.Bar
            fields = ('id', 'foo', 'description')
    
        def create(self, validated_data):
            foo = validated_data.pop('foo')
            bar = Bar.objects.create(
                foo=foo.id,
                **validated_data
            )
            return bar
    
        def update(self, instance, validated_data):
            foo = validated_data.pop('foo')
            instance.foo = foo
            instance.update(
                **validated_data
            )
            return instance
    

    在这种情况下,请求数据将是:

    { 'foo': {'id': '1', 'code': 'AAA'}, 'description': 'foo bar' }