You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:08:17