2

我是 Pydantic 的新手,并试图了解如何/是否可以创建一个新的类实例。我已通读 Pydantic 文档,但找不到类似的示例。

我的 python 代码(在 Pydantic 之前)看起来像:

class Person:
    def __init__(self, id):
        db_result = get_db_content(id)    #lookup id in a database and return a result
        self.name = db_result['name']      
        self.birth_year = db_result['birth_year']

p1 = Person(1234)
print(p1.name)

如果我想基于 id 创建一个 Person 实例,那么 Pydantic 中的相应代码会是什么样子?此外,Pydantic 是否可以为同一个
类拥有多个构造函数。例如:

p1 = Person(1234)
p2 = Person("Jane Doe")
4

4 回答 4

2

我不确定这是否是最“pydantic”的做事方式,但解决这个问题的方法之一是使用类方法。

class Person(BaseModel):
    id: int
    name: str
    birth_year: int

    @classmethod
    def from_id(cls, id: int) -> "Person":
        db_result = get_db_content(id)    #lookup id in a database and return a result
        return cls(**db_result)

p1 = Person.from_id(1234)
print(p1.name)
于 2021-06-22T14:56:41.270 回答
2

您可能会考虑的一种模式是为您的 pydantic 模型使用“集合”类。

正如人们所提到的,您的模型可以(应该)只是一个数据存储/验证器。您的集合类可以充当您的数据库接口,用于获取记录、记录组、执行查找等,并返回您的模型对象或模型对象列表。

pydantic 类示例:

class Person(BaseModel):
    id: str
    name: Optional[str]
    birth_year: Optional[int]

收藏类:

class PersonCollection:
    def __init__(self, db: pymongo.database.Database):
        self.collection = db.person_collection

    def find_people(self, criteria: dict) -> List[Person]:
        person_list: List[Person] = list()
        for person_data in self.collection.find(criteria):
            person_list.append(Person(**person_data))
        return person_list
    
     def save_person(self, person: Person):
        key = {"id": person.id}
        self.collection.update_one(
            filter=key,
            update={"$set": person.dict()},
            upsert=True
         )
于 2021-08-13T22:41:25.747 回答
2

目前这真的不可能。您必须使用类似Person(get_db_content()).

将来,您将能够拥有允许这样做的计算字段和上下文。

于 2020-05-14T08:29:45.843 回答
1

您可以为此使用标准的 __init__ :

from typing import Optional

from pydantic import BaseModel

def get_db_content(id):
    return {
        'name': f'hello {id}',
        'birth_year': 2010,
    }

class Person(BaseModel):
    id: str
    name: Optional[str]
    birth_year: Optional[int]
    def __init__(self, *a, **kw):
        super().__init__(*a, **kw)
        db_result = get_db_content(self.id)
        self.name = db_result['name']      
        self.birth_year = db_result['birth_year']

person = Person(id='15')
print(person.dict())
# {'id': '15', 'name': 'hello 15', 'birth_year': 2010}

虽然,我个人不会那样做。Pydantic 类旨在用作解析器/验证器,而不是用作功能齐全的对象实体。从这样的类中调用 DB 方法会直接将您的类与 db 代码耦合,并使测试更加困难。

我会这样做:

from pydantic import BaseModel

def get_db_content(id):
    return {
        'name': f'hello {id}',
        'birth_year': 2010,
    }

class Person(BaseModel):
    id: str
    name: str
    birth_year: int

person = Person(id='15', **get_db_content('15'))
print(person.dict())
# {'id': '15', 'name': 'hello 15', 'birth_year': 2010}

注意:代码示例应该是独立的并且可以按原样工作。

编辑:使用标准 dunder 构造函数而不是 @root_validator

于 2021-01-24T17:16:41.497 回答