迁移旧式PyObjectId
到最新的pydantic-v2版本,最简单的方法是使用带注释的验证器.
from typing import Any
from typing import Annotated, Union
from bson import ObjectId
from pydantic import PlainSerializer, AfterValidator, WithJsonSchema
def validate_object_id(v: Any) -> ObjectId:
if isinstance(v, ObjectId):
return v
if ObjectId.is_valid(v):
return ObjectId(v)
raise ValueError("Invalid ObjectId")
PyObjectId = Annotated[
Union[str, ObjectId],
AfterValidator(validate_object_id),
PlainSerializer(lambda x: str(x), return_type=str),
WithJsonSchema({"type": "string"}, mode="serialization"),
]
然后您可以通过以下方式在模型中使用它:
from pydantic import BaseModel
from pydantic import ConfigDict, Field
class MyCustomModel(BaseModel):
id: PyObjectId = Field(alias="_id")
model_config = ConfigDict(arbitrary_types_allowed=True)
使用测试一下类型适配器:
import pytest
from bson import ObjectId
from pydantic import TypeAdapter, ConfigDict
@pytest.mark.parametrize("obj", ["64b7992ba8f08069073f1055", ObjectId("64b7992ba8f08069073f1055")])
def test_pyobjectid_validation(obj):
ta = TypeAdapter(PyObjectId, config=ConfigDict(arbitrary_types_allowed=True))
ta.validate_python(obj)
@pytest.mark.parametrize("obj", ["64b7992ba8f08069073f1055", ObjectId("64b7992ba8f08069073f1055")])
def test_pyobjectid_serialization(obj):
ta = TypeAdapter(PyObjectId, config=ConfigDict(arbitrary_types_allowed=True))
ta.dump_json(obj)
即使使用最新的解决方案,该解决方案也能正常工作FastAPIv0.100.0+