
fastapi 默认按 pydantic 模型结构序列化响应,若需返回形如 {"tags": ["t1", "t2", "t3"]} 的扁平字符串列表(而非对象列表),应避免使用嵌套模型,改用基础类型(如 dict 或 list[str])作为 response_model,并在逻辑中直接提取字段值。
fastapi 默认按 pydantic 模型结构序列化响应,若需返回形如 {"tags": ["t1", "t2", "t3"]} 的扁平字符串列表(而非对象列表),应避免使用嵌套模型,改用基础类型(如 dict 或 list[str])作为 response_model,并在逻辑中直接提取字段值。
在 FastAPI 中,response_model 不仅用于文档生成(OpenAPI),更严格控制响应体的序列化结构与类型校验。你当前定义的 TagList 模型要求 tags 字段为 List[Tag],因此即使数据库只查出 name 字符串,FastAPI 仍会尝试将其构造成 Tag 实例(触发 from_attributes=True),最终输出带 {"name": "t1"} 的对象数组。
要获得目标格式 {"tags": ["t1", "t2", "t3"]},关键在于两点:
✅ 响应模型精简:不再使用 TagList,而采用 Dict[str, List[str]] 或更推荐的 Annotated[Dict[str, List[str]], ...];
✅ 数据提取精准:从 SQL 查询结果中直接取 name 字段的字符串值,而非构造 Tag 对象。
以下是优化后的端点实现:
from typing import Dict, List
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from sqlalchemy import text
router = APIRouter()
@router.get(
"/tags",
response_model=Dict[str, List[str]], # 明确声明返回结构:键为 str,值为字符串列表
status_code=200
)
def read_tags(db: Session = Depends(get_session)):
with db as session:
result = session.execute(text("SELECT name FROM tags"))
# 直接提取每行的第一个字段(即 name),转为字符串列表
tag_names = [row[0] for row in result]
return {"tags": tag_names}
⚠️ 注意事项:
- 若坚持使用 response_model=TagList,则必须让 Tag 模型的 nome 字段与数据库列名 name 一致(当前为 nome ≠ name),或在查询中显式别名:SELECT name AS nome FROM tags;但此方式仍会返回对象数组,不符合需求。
- 使用 response_model=dict(如原答案所示)虽能绕过校验,但牺牲了 OpenAPI 文档的准确性与类型提示,不推荐生产环境使用。
- 更佳实践是定义精准的响应模型,例如:
from pydantic import BaseModel class TagNameResponse(BaseModel): tags: List[str] # 然后设置 response_model=TagNameResponse
总结:FastAPI 的响应结构由 response_model 主导,而非返回字典的键名。始终让模型定义与预期 JSON 结构严格对齐,并在业务逻辑中做好数据清洗——这是实现简洁、可维护、自文档化 API 的核心原则。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










