FastAPI 不会为具有数组查询参数的查询生成文档。即:
GET /items?filter[name]=foo&filter[category]=bar&sort=-id,name
。
根据 Openapi 3.0 文档,它们支持 deepObject
查询参数 (/users?id[role]=admin&id[firstName]=Alex
)。但是如何使用 FastAPI 来做到这一点呢?
架构:
import re
from typing import Sequence, Generic, TypeVar, Dict, List, Optional, Any
from urllib.parse import unquote
from pydantic import BaseModel
from fastapi import Query, Request
class ListQueryParams(BaseModel):
query: str = Query(None, description="Search query", example='heart', min_length=1)
sort: List[str] = Query(None, description="Sorting", example='-id', min_length=2)
filter: Optional[Dict[str, Any]] = Query(dict(), description="Filters")
def __init__(self, request: Request, **data: Any):
super().__init__(**data)
self._set_filter(request)
self._set_sort(request)
def _set_filter(self, request: Request):
unquoted_params = unquote(str(request.query_params))
filters = re.findall(r'filter\[([a-z0-9-_]{2,})]', unquoted_params, re.IGNORECASE)
for key in filters:
value = request.query_params.get(f'filter[{key}]')
self.filter[key] = value
def _set_sort(self, request: Request):
self.sort = [field.strip() for field in request.query_params.get('sort', '').split(',') if field]
路线:
@router.get('', response_model=Page[ItemOut])
def list_items(params: ListQueryParams = Depends(), db: Session = Depends(get_db)):
return paginate(ItemsManager(db).get_items_list_query(query=params.query, filter=params.filter, sort=params.sort))
文档页面:
如果可能的话,我希望在文档中看到一个
filter
参数,其中包含方括号之间的归档名称及其值的输入。
更新:
我现在看到的唯一解决方案是手动扩展 openapi 架构:
from fastapi.openapi.utils import get_openapi
openapi_schema = get_openapi(...)
paths = openapi_schema['paths']
for path in paths:
for method in paths[path]:
if paths[path][method]['operationId'] == 'list_items_v1_items_get':
paths[path][method]['parameters'].extend([
{
'in': 'query',
'name': 'filter[name]',
'required': False
},
...
UPD
仍然不知道如何自动生成,所以停止使用此解决方案:
@router.get('', response_model=Page[ItemOut], openapi_extra={
'parameters': [
{
'in': 'query',
'name': 'filter[name]',
'required': False,
'schema': {
'minLength': 1,
'type': 'string',
'example': 'foobar'
}
},
...
遇到同样的问题,只找到一种解决方案。如果 GET 中的数组参数直接作为 kwarg 传递(如 this 文档中所示),Fastapi 会自动生成数组输入。但我不喜欢这种方式,因为它对应用程序架构非常不利,因为我想在单独的模块中控制查询参数。我也无法像这样输入参数:
from typing_extensions import Unpack
async def my_view(**filter_kwargs: Unpack[MyTypedDict]): ...
因为fastapi无法解析。因此,目前覆盖 openapi 设置是避免视图中出现大量参数的最佳方法。
更新!解决方案:
抱歉信息有误,我在20分钟后才解决:
class Filters(BaseModel):
string_array: list[str] = Field(Query())
@router.get("/test")
async def test(
filter_kwargs: Filters = Depends(),
):
return {"filter_kwargs": filter_kwargs.string_array}