如何在 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]))
在带有 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]))