Package: fastapi-querysets
FastAPI QuerysetsDocumentation:https://fastapi-querysets.readthedocs.ioSource Code:https://github.com/Nikakto/fastapi-querysetsWhy to use?While you are developing FastAPI applications you are using databases with ORM. Most of the endpoints are view of database tables and require restrict queryset by filtering, pagination, ordering. This project is generic and reusable way to create restricted querysets for your endpoints.Supported ORMTortoise ORMRequirementspython >=3.8,<4.0fastAPI >= 0.78tortoise-orm >= 0.18.1Installationpip install fastapi-querysetsQuick tutorialTortoise modelLet’s start with our model# models/tortoise.pyimportdatetimefromtypingimportOptionalfromtortoiseimportModelfromtortoiseimportfieldsclassTask(Model):id:int=fields.IntField(pk=True)approved:Optional[bool]=fields.BooleanField(default=False,null=True)code:str=fields.CharField(max_length=6)created_at:datetime.datetime=fields.DatetimeField(default=datetime.datetime.now)Pydantic modelCreate database representation model# models/pydantic.pyfromtortoise.contrib.pydanticimportpydantic_model_creatorfrommyproject.models.tortoiseimportTaskTaskModelOut=pydantic_model_creator(Task,name="TaskModelOut",include=("id","approved","code","created_at"),)RouterQuerySetFiltersWe have a number of fields we want to let our users filter based on them. We create a RouterQuerySetFilter for this. Filter class is argument forFastAPI.Dependsat endpoint.You require to define ORM filter keyword, type of data and setup source of data (Query,Path,Body, etc).# querysets_filters.pyimportdataclassesimportdatetimefromtypingimportOptionalfromfastapiimportQuery@dataclasses.dataclassclassRouterQuerySetFilter:id__in:Optional[list[int]]=Query(None,alias='id[]')approved:Optional[bool]=Query(None)approved__isnull:Optional[bool]=Query(None)code:Optional[str]=Query(None)created_at__lte:Optional[datetime.datetime]=Query(None)created_at__gte:Optional[datetime.datetime]=Query(None)Model QuerysetConfigureRouterQuerysetproperties# querysets.pyfromfastapi_querysets.mixins.filtersimportFilterMixinfromfastapi_querysets.mixins.filtersimportFilterNegationMixinfromfastapi_querysets.mixins.orderingimportOrderingMixinfromfastapi_querysets.mixins.paginationimportPaginationMixinfromfastapi_querysets.mixins.paginationimportRouterPaginationfromfastapi_querysets.querysetimportRouterQuerySetfrommyproject.models.tortoiseimportTaskfrommyproject.querysets_filtersimportRouterQuerySetFilterclassTasksRouterQuerySet(FilterMixin,FilterNegationMixin,OrderingMixin,PaginationMixin,RouterQuerySet):filter_class=RouterQuerySetFilterordering_default="id"ordering_fields=("id","approved","code","created_at",)pagination_class=RouterPaginationmodel=TaskApplicationCreate application, register list, list with pagination and retrieve endpoints.# app.pyfromfastapiimportFastAPIfromtortoise.contrib.fastapiimportregister_tortoisefromtortoise.querysetimportQuerySetfrommyproject.models.pydanticimportTaskModelOutfrommyproject.models.tortoiseimportTaskfrommyproject.querysetsimportTasksRouterQuerySetapp=FastAPI()register_tortoise(app,db_url="sqlite://:memory:",modules={"models":["myproject.models.tortoise"]},generate_schemas=True,add_exception_handlers=True,)@app.get("tasks/",response_model=list[TaskModelOut])asyncdeftasks_list_paginated(queryset:QuerySet[Task]=TasksRouterQuerySet())->list[TaskModelOut]:returnawaitTaskModelOut.from_queryset(queryset)@app.get("tasks/paginated",response_model=list[TaskModelOut])asyncdeftasks_list_paginated(queryset:QuerySet[Task]=TasksRouterQuerySet().paginated)->list[TaskModelOut]:returnawaitTaskModelOut.from_queryset(queryset)@app.get("tasks/{instance_id}",response_model=list[TaskModelOut])asyncdeftasks_retrieve(task:QuerySet[Task]=TasksRouterQuerySet().instance)->list[TaskModelOut]:returnTaskModelOut.from_orm(task)RequestsListOn request effective queryset will be filtered and ordered by query params.For example, user has requested endpoint with some query params{"created_at__lte":"2023-01-01T00:00:00","approved":false,"ordering[]":"created_at",}Request URL looks likehttp://localhost:8000/tasks/?created_at__lte=2023-01-01T00:00:00&approved=false&ordering[]=created_atEffective queryset at the endpoint method will be(Task.filter(created_at__lte=datetime.datetime(2023,1,1,0,0,0),approved=False).order_by("created_at"))List paginatedLike not paginated endpoint at this queryset will be filtered, ordering and additional paginated.For example, user has requested endpoint with some query params{"page":2,"per_page":10,"created_at__lte":"2023-01-01T00:00:00","approved":false,"ordering[]":"created_at",}Request URL looks likehttp://localhost:8000/tasks/?page=2&per_page=10&created_at__lte=2023-01-01T00:00:00&approved=false&ordering[]=created_atEffective queryset at endpoint method will be(Task.filter(created_at__lte=datetime.datetime(2023,1,1,0,0,0),approved=False).order_by("created_at").offset(10).limit(10))As well as toResponsewill be added pagination information. Pagination information always matches effective queryset{"x-page":"2","x-pages":"4","x-per-page":"10","x-total":"32"}RetrieveRequest URL looks likehttp://localhost:8000/tasks/10/Endpoint method will getTaskwithid == 10as argumenttask.IfTaskwithid == 10does not exist then endpoint returnResponse(404)