pydantic根据字典

时间:2020-06-08 17:09:03

标签: python pydantic

我只是最近才开始研究pydantic的文档,但是我没有看到直接从dict对象生成模型的直接方法。有没有一种方法可以生成一个供以后检索并保存以供以后使用的方法?

这是我拥有的数据的样本。

{
    'id': '424c015f-7170-4ac5-8f59-096b83fe5f5806082020',
    'contacts': [{
        'displayName': 'Norma Fisher',
        'id': '544aa395-0e63-4f9a-8cd4-767b3040146d'
    }],
    'startTime': '2020-06-08T09:38:00+00:00'
}

期待与...相似的模型

class NewModel(BaseModel):
    id: str
    contacts: list
    startTime: str

4 个答案:

答案 0 :(得分:2)

没有确切的方法,但是如果您知道字段类型,则可以使用create_model()创建模型。

或者有datamodel-code-generator(单独的程序包),它允许您从架构定义中生成模型。

答案 1 :(得分:2)

您可以使用MyModel.parse_obj(my_dict)从词典中生成模型。根据{{​​3}} –

这与模型的__init__方法非常相似,除了它采用字典而不是关键字参数。

答案 2 :(得分:2)

我使用此方法在运行时使用字典定义生成模型。这种方法也允许您定义嵌套模型。字段类型语法借鉴自 create_model 方法。

from pydantic import create_model
m = {
    "a":(int,...),
    "b":{
        "c":(str,"hi"),
        "d":{
            "e":(bool,True),
            "f":(float,0.5)
        }
    }
}

def dict_model(name:str,dict_def:dict):
    fields = {}
    for field_name,value in dict_def.items():
        if isinstance(value,tuple):
            fields[field_name]=value
        elif isinstance(value,dict):
            fields[field_name]=(dict_model(f'{name}_{field_name}',value),...)
        else:
            raise ValueError(f"Field {field_name}:{value} has invalid syntax")
    return create_model(name,**fields)

model = dict_model("some_name",m)

答案 3 :(得分:0)

虽然我喜欢 @data_wiz 字典定义,但这里有一个替代建议,它基于我需要即时获取简单的 JSON 响应,这些响应通常是 CamelCase 关键元素,并且能够将其处理为 Python 风格的类。

然而,使用标准函数 JSON 可以轻松转换为 Dict! 我想以 Pythonic 风格来处理这个问题 我还希望能够有一些类型覆盖将字符串转换为 pythonic 类型 我还想指出可选的元素。这就是我开始喜欢 Pydantic 的地方。

以下代码片段可以从来自 JSON API 响应的实际数据 Dict 生成模型,因为键是驼峰式的,它会将它们转换为 pythonic 蛇样式,但保留驼峰式作为别名。

这个 pydantic 别名可以轻松使用转换为 Dict 的 JSON,无需密钥转换,也可以直接导出 JSON 格式的输出。注意观察动态模型 DynamicModel.__config__.allow_population_by_field_name = True 的配置,这允许从别名或 Pythonic 字段名称创建 dynamicModel。

此代码功能不全,目前无法处理列表,但对于简单情况,它对我来说效果很好。 使用示例在 pydanticModelGenerator 的文档字符串中

from inflection import underscore
from typing import Any, Dict, Optional
from pydantic import BaseModel, Field, create_model


class ModelDef(BaseModel):
    """Assistance Class for Pydantic Dynamic Model Generation"""

    field: str
    field_alias: str
    field_type: Any


class pydanticModelGenerator:
    """
    Takes source_data:Dict ( a single instance example of something like a JSON node) and self generates a pythonic data model with Alias to original source field names. This makes it easy to popuate or export to other systems yet handle the data in a pythonic way.
    Being a pydantic datamodel all the richness of pydantic data validation is available and these models can easily be used in FastAPI and or a ORM

    It does not process full JSON data structures but takes simple JSON document with basic elements

    Provide a model_name, an example of JSON data and a dict of type overrides

    Example:

    source_data = {'Name': '48 Rainbow Rd',
        'GroupAddressStyle': 'ThreeLevel',
        'LastModified': '2020-12-21T07:02:51.2400232Z',
        'ProjectStart': '2020-12-03T07:36:03.324856Z',
        'Comment': '',
        'CompletionStatus': 'Editing',
        'LastUsedPuid': '955',
        'Guid': '0c85957b-c2ae-4985-9752-b300ab385b36'}

    source_overrides = {'Guid':{'type':uuid.UUID},
            'LastModified':{'type':datetime },
            'ProjectStart':{'type':datetime },
            }
    source_optionals = {"Comment":True}

    #create Model
    model_Project=pydanticModelGenerator(
        model_name="Project",
        source_data=source_data,
        overrides=source_overrides,
        optionals=source_optionals).generate_model()

    #create instance using DynamicModel
    project_instance=model_Project(**project_info)

    """

    def __init__(
        self,
        model_name: str = None,
        source_data: str = None,
        overrides: Dict = {},
        optionals: Dict = {},
    ):
        def field_type_generator(k, overrides, optionals):
            pass
            field_type = str if not overrides.get(k) else overrides[k]["type"]
            return field_type if not optionals.get(k) else Optional[field_type]

        self._model_name = model_name
        self._json_data = source_data
        self._model_def = [
            ModelDef(
                field=underscore(k),
                field_alias=k,
                field_type=field_type_generator(k, overrides, optionals),
            )
            for k in source_data.keys()
        ]

    def generate_model(self):
        """
        Creates a pydantic BaseModel
        from the json and overrides provided at initialization
        """
        fields = {
            d.field: (d.field_type, Field(alias=d.field_alias)) for d in self._model_def
        }
        DynamicModel = create_model(self._model_name, **fields)
        DynamicModel.__config__.allow_population_by_field_name = True
        return DynamicModel