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

A G*_*A G 14 python rest 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()
Run Code Online (Sandbox Code Playgroud)

如果我想允许过滤,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)
Run Code Online (Sandbox Code Playgroud)

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

或者手动包含我想要过滤的所有字段作为可选查询参数,然后检查每个参数,然后过滤是否存在唯一的方法?

Hey*_*Man 4

这是可能的,但还不完美:

from fastapi.params import Depends

@app.get("/items/")
async def read_item(item: Item = Depends()):
    pass
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅FastAPI 文档。

缺点是可能需要在 Item 类中指定参数。可以编写具有所有可选参数的子类(例如,如此处所述。它适用于该类的实例,但 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]))
Run Code Online (Sandbox Code Playgroud)