Pydantic datetime字段在MongoDB中存为字符串,需转为Mongo Date类型
解决MongoDB中日期字段存储为String而非Date类型的问题
问题场景
尝试将日期存储到MongoDB集合时,createdAt和updatedAt字段被存储为String类型,需要改为Mongo原生的Date类型。对应的Pydantic模型和入库代码如下:
Pydantic模型代码
from datetime import datetime, timezone from uuid import UUID, uuid4 from pydantic import BaseModel, Field, constr, Optional def datetime_now() -> datetime: return datetime.now(timezone.utc) class Project(BaseModel): id: UUID = Field(default_factory=uuid.uuid4, alias="_id") title: str = Field(constr(max_length=30)) description: str = Field(constr(max_length=200)) createdAt: datetime = Field(default_factory=datetime_now) updatedAt: datetime = Field(default_factory=datetime_now) createdBy: Optional[str] = None updatedBy: Optional[str] = None archived: Optional[bool] = False deleted: Optional[bool] = False
数据入库代码
from fastapi import APIRouter, Request, Body, Header, status from typing import Optional router = APIRouter() @router.post( "/", response_description="Create a new project", status_code=status.HTTP_201_CREATED, response_model=[], ) def create_project( request: Request, project: Project = Body(...), Authorization: Optional[str] = Header(None), ): print(request.state.jwt_content) project = jsonable_encoder(project) project['createdBy'] = request.state.jwt_content['emp_code'] project['updatedBy'] = request.state.jwt_content['emp_code'] new_project = request.app.database["projects"].insert_one(project) created_project = request.app.database["projects"].find_one( {"_id": new_project.inserted_id} ) return created_project
参考附图:手动设置的
createdAt为Date类型,而自动生成的updatedAt为String类型。
问题原因
jsonable_encoder会将Python的datetime对象转换为ISO格式的字符串,MongoDB接收字符串后会直接存储为String类型,而非原生Date类型。
解决方案
避免使用jsonable_encoder转换整个模型对象,改用Pydantic的model_dump(V2版本)或dict()(V1版本)方法,保留datetime对象的原始类型,MongoDB会自动将其识别为Date类型存储。
修改后的入库代码
@router.post( "/", response_description="Create a new project", status_code=status.HTTP_201_CREATED, response_model=[], ) def create_project( request: Request, project: Project = Body(...), Authorization: Optional[str] = Header(None), ): print(request.state.jwt_content) # 替换jsonable_encoder为model_dump(Pydantic V2),保留datetime对象 project = project.model_dump(by_alias=True) # 如果是Pydantic V1,使用project.dict(by_alias=True) project['createdBy'] = request.state.jwt_content['emp_code'] project['updatedBy'] = request.state.jwt_content['emp_code'] new_project = request.app.database["projects"].insert_one(project) created_project = request.app.database["projects"].find_one( {"_id": new_project.inserted_id} ) return created_project
关键说明
by_alias=True参数确保模型中使用alias="_id"的id字段被转换为MongoDB需要的_id键。- 保留
datetime对象后,MongoDB驱动会自动将其序列化为原生Date类型存储,无需额外转换。
内容的提问来源于stack exchange,提问作者raju
相关产品推荐
相关产品推荐

