如何在 FastAPI 中对模型的所有字段启用过滤

How to enable filtering on all fields of a model in FastAPI

在带有 restframework 的 Django 中,您可以这样做:

class Item(models.Model):
    id = models.IntegerField()
    name = models.CharField(max_length=32)
    another_attribute = models.CharField(max_length=32)
    ...
    (more attributes)
    ...
    yet_another_attribute = models.CharField(max_length=32)

class ItemViewSet(viewsets.ReadOnlyModelViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class = ItemSerializer
    filterset_fields = '__all__' # <- this enables filtering on all fields
    queryset = Item.objects.all()

如果我想允许过滤,filterset_fields = '__all__' 将允许我执行类似 api/item/?(attribute)=(value) 的操作并允许我过滤任何属性

我正在学习教程 (https://fastapi.tiangolo.com/tutorial/sql-databases/#crud-utils),看起来涉及很多手动过滤:

from fastapi_sqlalchemy import db

class Item(BaseModel):
    id: int
    name: str
    another_attribute: str
    ...
    (more attributes)
    ...
    yet_another_attribute: str

# is it necessary to manually include all the fields I want to filter on as optional query parameters?
@app.get("/items/")
async def read_item(
    db: Session,
    id: Optional[int] = None,
    name: Optional[str] = None,
    another_attribute: Optional[str] = None,
    ...
    (more attributes)
    ...
    yet_another_attribute: Optional[str] = None
):
    # and then I'd need to check if the query parameter has been specified, and if so, filter it.
    queryset = db.session.query(Item)
    if id:
        queryset = queryset.filter(Item.id == id)
    if name:
        queryset = queryset.filter(Item.name == name)
    if another_attribute:
        queryset = queryset.filter(Item.another_attribute == another_attribute)
    ...
    (repeat above pattern for more attributes)
    ...
    if yet_another_attribute:
        queryset = queryset.filter(Item.yet_another_attribute == yet_another_attribute)

实现上述行为的首选方式是什么?是否有任何软件包可以让我免于进行大量手动过滤,从而使我的行为与 Django Rest Framework 视图集一样方便?

或者是手动将我要过滤的所有字段作为可选查询参数包括在内,然后检查每个参数,然后过滤(如果存在)是唯一的方法吗?

当然,它在文档中有描述。 试试这个,省略号根据需要标记字段。

id: Optional[int] = Header(...)  # Header, path or any another place 

https://fastapi.tiangolo.com/tutorial/query-params-str-validations/

有可能但还不完美:

from fastapi.params import Depends

@app.get("/items/")
async def read_item(item: Item = Depends()):
    pass

详情见FastAPI Doku

缺点是参数是必需的,可能在 class 项中指定。可以使用所有可选参数编​​写一个 subclass(例如,如 here 所述)。它适用于 class 的实例,但 FastAPI 似乎并未反映 API 文档中的实例。如果有人对此有解决方案,我很乐意学习。

或者,您可以拥有多个模型,如所述 。但是我不喜欢这种方式。

要回答您的第二个问题,您可以像这样访问所有通用参数:

@app.get("/items/")
async def read_item(
    db: Session,
    id: Optional[int] = None,
    name: Optional[str] = None,
    another_attribute: Optional[str] = None,
    ...
    (more attributes)
    ...
    yet_another_attribute: Optional[str] = None
):
    params = locals().copy()
    ...
    for attr in [x for x in params if params[x] is not None]:
        query = query.filter(getattr(db_model.Item, attr).like(params[attr]))