如何在pydantic模型中解析ObjectId?

ros*_*hii 7 python parsing mongodb objectid pydantic

我正在尝试将 MongoDB 记录解析为 pydantic 模型,但未能这样做 ObjectId

据我了解,我需要为 ObjectId 设置验证器,并尝试扩展 ObjectId 类并validator使用 ObjectId将装饰器添加到我的类中。我做了如下。

from pydantic import BaseModel, validator
from bson.objectid import ObjectId


class ObjectId(ObjectId):
    pass
    @classmethod
    def __get_validators__(cls):
        yield cls.validate
    @classmethod
    def validate(cls, v):
        if not isinstance(v, ObjectId):
            raise TypeError('ObjectId required')
        return str(v)


class User(BaseModel):
    who: ObjectId


class User1(BaseModel):
    who: ObjectId
    @validator('who')
    def validate(cls, v):
        if not isinstance(v, ObjectId):
            raise TypeError('ObjectId required')
        return str(v)

data = {"who":ObjectId('123456781234567812345678')}
Run Code Online (Sandbox Code Playgroud)

不幸的是,两个“解决方案”都失败了,如下所示:

>>> test = User(**data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 274, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for User
id
  field required (type=value_error.missing)
Run Code Online (Sandbox Code Playgroud)
>>> test = User1(**data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 274, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for User1
who
  ObjectId required (type=type_error)
Run Code Online (Sandbox Code Playgroud)

我在这里肯定缺少一些东西。

Tom*_*cik 14

您的第一个测试用例工作正常。问题在于你如何覆盖ObjectId.

from pydantic import BaseModel
from bson.objectid import ObjectId as BsonObjectId


class PydanticObjectId(BsonObjectId):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not isinstance(v, BsonObjectId):
            raise TypeError('ObjectId required')
        return str(v)


class User(BaseModel):
    who: PydanticObjectId


print(User(who=BsonObjectId('123456781234567812345678')))

Run Code Online (Sandbox Code Playgroud)

印刷

who='123456781234567812345678'
Run Code Online (Sandbox Code Playgroud)

只有 pydantic 应该使用 pydantic 类型。Mongo 将为您提供 bsons ObjectId。所以用真实的 ObjectId 实例化你的数据。所以data = {"who":ObjectId('123456781234567812345678')}是错误的,因为它使用您的子 ObjectId 类。

  • “Pydantic2”的新解决方案? (2认同)

小智 10

另一种方法是使用 pydantic,我从另一个来源发现它很有用:

在 models 文件夹中定义一个名为 PyObjectId.py 的文件。

from pydantic import BaseModel, Field as PydanticField
from bson import ObjectId

class PyObjectId(ObjectId):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate
    @classmethod
    def validate(cls, v):
        if not ObjectId.is_valid(v):
            raise ValueError("Invalid objectid")
        return ObjectId(v)
    @classmethod
    def __modify_schema__(cls, field_schema):
        field_schema.update(type="string")
Run Code Online (Sandbox Code Playgroud)

然后您可以在任何目标文件中使用它,例如 users.py

from models.PyObjectId import PyObjectId
from pydantic import BaseModel, Field as PydanticField
from bson import ObjectId
class Users(BaseModel):
    id: PyObjectId = PydanticField(default_factory=PyObjectId, alias="_id")
    class Config:
        allow_population_by_field_name = True
        arbitrary_types_allowed = True #required for the _id 
        json_encoders = {ObjectId: str}
Run Code Online (Sandbox Code Playgroud)


mil*_*ani 7

MongoDB 和 FastAPI 入门

蒙戈开发者

此代码帮助您使用 json 编码器

from bson import ObjectId
from pydantic import BaseModel


class ObjId(ObjectId):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v: str):
        try:
            return cls(v)
        except InvalidId:
            raise ValueError("Not a valid ObjectId")


class Foo(BaseModel):
    object_id_field: ObjId = None

    class Config:
        json_encoders = {
            ObjId: lambda v: str(v),
        }



obj = Foo(object_id_field="60cd778664dc9f75f4aadec8")
print(obj.dict())
# {'object_id_field': ObjectId('60cd778664dc9f75f4aadec8')}
print(obj.json())
# {'object_id_field': '60cd778664dc9f75f4aadec8'}
Run Code Online (Sandbox Code Playgroud)

更新:

您可以在 pydantic 模型中使用此 Field 类型:

from bson import ObjectId as BaseObjectId

class ObjectId(str):
"""Creating a ObjectId class for pydantic models."""

    @classmethod
    def validate(cls, value):
        """Validate given str value to check if good for being ObjectId."""
        try:
            return BaseObjectId(str(value))
        except InvalidId as e:
            raise ValueError("Not a valid ObjectId") from e

    @classmethod
    def __get_validators__(cls):
        yield cls.validate
Run Code Online (Sandbox Code Playgroud)