FastAPI构建按日期查询MongoDB股票预测接口遇422错误求助
问题原因及解决方案
核心问题分析
- 422错误根源:接口路径参数声明为
datetime.datetime,但传入的是YYYY-MM-DD格式的纯日期字符串,FastAPI无法将其自动解析为带时间的datetime对象,导致参数验证失败。 - MongoDB查询不匹配:数据库中存储的日期是带UTC时区的完整
datetime(如2023-05-19T00:00:00.000+00:00),直接用datetime.date对象查询会匹配不到数据。 - 模型字段不匹配:声明的
Predictions模型包含多余的symbol字段,与数据库实际的id_、date、predicted三个字段结构不符,会导致数据解析错误。
修正步骤及代码
1. 调整路径参数类型
将接口参数从datetime.datetime改为datetime.date,FastAPI会自动处理YYYY-MM-DD格式的输入。
2. 构造正确的MongoDB日期查询条件
由于数据库存储的是带时间的UTC日期,需要查询指定日期当天00:00到次日00:00的所有文档,确保匹配该日期的所有预测数据。
3. 修正数据模型字段
移除多余的symbol字段,确保模型与数据库文档结构一致;这里默认数据库使用MongoDB原生的_id作为ID字段,若实际是自定义id_,可对应修改模型字段别名。
修正后的完整代码
from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field from bson import ObjectId from typing import List import motor.motor_asyncio import datetime from datetime import timezone app = FastAPI() client = motor.motor_asyncio.AsyncIOMotorClient("mongodb://localhost:27017/") db = client.signal_API 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") # 修正模型,匹配数据库实际字段 class Predictions(BaseModel): id: PyObjectId = Field(default_factory=PyObjectId, alias="_id") date: datetime.datetime = Field(...) # 对应数据库的带时区datetime字段 predicted: float = Field(...) class Config: allow_population_by_field_name = True arbitrary_types_allowed = True json_encoders = {ObjectId: str} schema_extra = { "example": { "date": "2023-04-28T00:00:00.000+00:00", "predicted": 0.0758, } } @app.get( "/{date}", response_description="获取指定日期的股票预测数据", response_model=List[Predictions] ) async def list_predictions_by_date(date: datetime.date): # 构造UTC时间范围:当天00:00到次日00:00 start_date = datetime.datetime(date.year, date.month, date.day, tzinfo=timezone.utc) end_date = start_date + datetime.timedelta(days=1) # 查询该时间范围内的所有文档 predictions = await db["predictions_live_API"].find({ "date": { "$gte": start_date, "$lt": end_date } }).to_list(1000) if not predictions: raise HTTPException(status_code=404, detail=f"未找到日期{date}的预测数据") return predictions
额外说明
- 如果数据库中实际的ID字段是自定义的
id_而非MongoDB默认的_id,只需将模型中的id字段改为id: str = Field(..., alias="id_")(根据id_的实际类型调整)。 - 测试接口时,直接传入
YYYY-MM-DD格式的日期即可,比如访问http://localhost:8000/2023-05-19。
内容的提问来源于stack exchange,提问作者rcardinaux
相关产品推荐
相关产品推荐

