|
|
from enum import Enum |
|
|
from typing import Annotated, Dict, Any, Optional, Type |
|
|
|
|
|
from pydantic import BeforeValidator, BaseModel, ConfigDict, Field |
|
|
from bson import ObjectId |
|
|
|
|
|
PyObjectId = Annotated[str, BeforeValidator(str)] |
|
|
|
|
|
class MongoBaseModel(BaseModel): |
|
|
id: Optional[PyObjectId] = Field(alias="_id", default_factory=ObjectId) |
|
|
|
|
|
model_config = ConfigDict( |
|
|
populate_by_name=True, |
|
|
arbitrary_types_allowed=True, |
|
|
json_encoders={PyObjectId: str}, |
|
|
) |
|
|
|
|
|
def to_mongo(self): |
|
|
result = self.model_dump(by_alias=True, mode='json', exclude={'id',}) |
|
|
result['_id'] = ObjectId(self.id) |
|
|
return result |
|
|
|
|
|
@classmethod |
|
|
def from_mongo(cls, data: Dict[str, Any]): |
|
|
def restore_enums(inst: Any, model_cls: Type[BaseModel]) -> None: |
|
|
for name, field in model_cls.__fields__.items(): |
|
|
value = getattr(inst, name) |
|
|
if field and isinstance(field.annotation, type) and issubclass(field.annotation, Enum): |
|
|
setattr(inst, name, field.annotation(value)) |
|
|
elif isinstance(value, BaseModel): |
|
|
restore_enums(value, value.__class__) |
|
|
elif isinstance(value, list): |
|
|
for i, item in enumerate(value): |
|
|
if isinstance(item, BaseModel): |
|
|
restore_enums(item, item.__class__) |
|
|
elif isinstance(field.annotation, type) and issubclass(field.annotation, Enum): |
|
|
value[i] = field.annotation(item) |
|
|
elif isinstance(value, dict): |
|
|
for k, v in value.items(): |
|
|
if isinstance(v, BaseModel): |
|
|
restore_enums(v, v.__class__) |
|
|
elif isinstance(field.annotation, type) and issubclass(field.annotation, Enum): |
|
|
value[k] = field.annotation(v) |
|
|
|
|
|
if data is None: |
|
|
return None |
|
|
instance = cls(**data) |
|
|
restore_enums(instance, instance.__class__) |
|
|
return instance |
|
|
|