首页 > 解决方案 > 使用 DRF 序列化器验证包含动态键的嵌套字典

问题描述

我正在为现有 API 编写序列化程序,以便为项目自动生成 OpenAPI 文档。我遇到的问题之一是定义序列化程序来验证从某些视图返回的数据。

这是数据的结构:

{
    "airmass_data": {
        "site-A": {
            "times": ["2021-09-09T09:54","2021-09-09T10:04"],
            "airmasses": [2.900041850251779, 2.687634707193725]
        },
        "site-B": {
            "times": ["2021-09-09T09:54","2021-09-09T10:04"],
            "airmasses": [2.900041850251779, 2.687634707193725]
        },
                ...
    },
    "airmass_limit": 3.19
}

可以有任意数量的“site-X”键,它们是动态生成的——这绝对是我的问题的一部分。

以下是我设置序列化程序的方式,我认为这与我的字典结构最匹配:

class SiteAirmassDatumSerializer(serializers.Serializer):
    times = serializers.ListField(child=serializers.CharField())
    airmasses = serializers.ListField(child=serializers.FloatField())


class SiteAirmassSerializer(serializers.Serializer):
    site = SiteAirmassDatumSerializer(source='*')


class AirmassSerializer(serializers.Serializer):
    airmass_data = SiteAirmassSerializer(source='*')
    airmass_limit = serializers.FloatField()

但是,当将我的字典传递给序列化程序并尝试对其进行验证时, serializer.errors 属性具有:

{
  "airmass_data": {
    "site": [
      "This field is required."
    ]
  }
}

有没有一种好方法可以编写一组序列化程序来处理动态生成的密钥?我主要是想写这个来验证返回字典的一般结构——不一定是其中的键。我对使用序列化程序感兴趣的原因是利用 DRF 的 OpenAPI 生成功能。

编辑:

还尝试DictField在序列化程序中使用 a ,如下所示:

class SiteAirmassDatumSerializer(serializers.Serializer):
    times = serializers.ListField(child=serializers.CharField())
    airmasses = serializers.ListField(child=serializers.FloatField())


class SiteAirmassSerializer(serializers.Serializer):
    site = DictField(child=SiteAirmassDatumSerializer(), source='*')


class AirmassSerializer(serializers.Serializer):
    airmass_data = DictField(child=SiteAirmassSerializer(), source='*')
    airmass_limit = serializers.FloatField()

尝试验证上述结构时,出现以下错误:

{
  "airmass_data": {
    "site-A": {
      "site": [
        "This field is required."
      ]
    }
  }
}

标签: pythondjangodjango-rest-framework

解决方案


我建议更改您的数据结构并使用列表而不是字典:

{
"airmass_data": [
     {
        "site_name": "site-A"
        "times": ["2021-09-09T09:54","2021-09-09T10:04"],
        "airmasses": [2.900041850251779, 2.687634707193725]
    },
    {
        "site_name": "site-B"
        "times": ["2021-09-09T09:54","2021-09-09T10:04"],
        "airmasses": [2.900041850251779, 2.687634707193725]
    },
            ...
],
"airmass_limit": 3.19

}


推荐阅读