将模型字段序列化为嵌套 object/dict

Serialize model fields into nested object/dict

设想以下模型:

class Person(models.Model):
    name = models.CharField()
    address_streetname = models.CharField()
    address_housenumber = models.CharField()
    address_zip = models.CharField()

我有一个公开所有字段的 django rest 框架 ModelSerializer。 但我希望能够将地址字段序列化为字典。因此,当序列化为 json 时,输出将是:

{
    name: 'Some name',
    address: {
        streetname: 'This is a test',
        housenumber: '23',
        zip: '1337',
    }
}

我尝试创建一个 AddressSerializer

class Address(object):
    ...

class AddressSerializer(serializers.Serializer):
    streetname = serializers.CharField()
    housenumber = serializers.CharField()
    zip = serializers.CharField()
    ...

然后设置PersonSerializer.address使用AddressSerializer

class PersonSerializer(serializers.ModelSerializer):
    ...
    address = AddressSerializer()

这导致我的架构正确。我使用 drf-yasg 生成 swagger 文档。它查看序列化程序以生成正确的模型定义。所以序列化程序需要表示模式。

这就是我现在所在的位置。显然现在它失败了,因为 Person 模型中没有 address 属性。你会如何解决这个问题?

你可以在序列化器中定义一个property:

class Person(models.Model):
    name = models.CharField()
    address_streetname = models.CharField()
    address_housenumber = models.CharField()
    address_zip = models.CharField()

    @property
    def address(self):
        return {'streetname': self.address_streetname,
                'housenumber': self.address_housenumber,
                'zip': self.address_zip}

DRF-doc for source 说,

The value source='*' has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.


所以,试试这个,

class AddressSerializer(serializers.Serializer):
    streetname = serializers.CharField(source='address_streetname')
    housenumber = serializers.CharField(source='address_housenumber')
    zip = serializers.CharField(source='address_zip')


class PersonSerializer(serializers.ModelSerializer):
    # .... your fields
    address = AddressSerializer(source='*')

    class Meta:
        fields = ('address', 'other_fields')
        model = Person