[英]How to parse ObjectId in a pydantic model?
我正在嘗試將 MongoDB 記錄解析為 pydantic 模型,但沒有為ObjectId
這樣做
據我了解,我需要為 ObjectId 設置驗證器,並嘗試擴展 ObjectId 類並使用 ObjectId 將validator
裝飾器添加到我的類中。 我做了如下。
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')}
不幸的是,這兩個“解決方案”都失敗了,如下所示:
>>> 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)
>>> 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)
這里肯定有一些我想念的東西。
您的第一個測試用例工作正常。 問題在於您如何覆蓋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')))
印刷
who='123456781234567812345678'
只有 pydantic 應該使用 pydantic 類型。 Mongo 將為您提供 bsons ObjectId。 所以用真實的 ObjectId 實例化你的數據。 所以data = {"who":ObjectId('123456781234567812345678')}
是錯誤的,因為它使用您的子 ObjectId 類。
另一種方法是使用 pydantic,我發現從另一個來源有用的是:
在模型文件夾中定義一個名為 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")
然后你可以在你的任何目標文件中使用它,比如 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}
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'}
查看答案和其他文章,我使用以下對象並使用ENCODERS_BY_TYPE
中的pydantic.json
使編碼全局從str
到ObjectId
,反之亦然。
import bson
import bson.errors
from pydantic.json import ENCODERS_BY_TYPE
class ObjectId(bson.ObjectId):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
raise_error = False
try:
if isinstance(v, str):
v = bson.ObjectId(v)
if (
not isinstance(v, (bson.ObjectId, cls))
or not bson.ObjectId.is_valid(v)
):
raise_error = True
except bson.errors.InvalidId:
raise_error = True
if raise_error:
raise ValueError("Invalid ObjectId")
return v
@classmethod
def __modify_schema__(cls, field_schema):
field_schema.update(type="string")
if ObjectId not in ENCODERS_BY_TYPE:
ENCODERS_BY_TYPE[ObjectId] = str
ENCODERS_BY_TYPE[bson.ObjectId] = str
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.