FastAPIwee
FastAPIwee copied to clipboard
Feature: filters, ordering, pagination
Implement support for query filters, ordering and pagination
expect this!
I implemented this in my own project (by subclassing ListFastAPIView). is it ok if I just post the code here instead of making a PR?
@YoilyL, hi. Sure, would be nice)
from fastapi import Depends, Query
from fastapiwee.crud import viewsets
from fastapiwee.pwpd import PwPdModel
from pydantic import BaseModel, Field, create_model
def list_serializer(model):
pd_model = PwPdModel.make_serializer(model)
fields: dict[str, Any] = {name: (Optional[list[field.type_]], Field(Query([field.default]))) if field.default else (Optional[list[field.type_]], Field(Query(None))) for name, field in pd_model.__fields__.items()}
model2 = create_model("ListPkModel",**fields)
return model2
class ListParams(BaseModel):
filters: BaseModel
sort: tuple[str, str]
pagination: tuple[int, int]
class ListFastAPIView(viewsets.ListFastAPIView):
_params: ListParams
def __call__(self):
sort_col, sort_dir = self._params.sort
order_by = getattr( getattr(self.MODEL, sort_col), sort_dir)()
query = self._get_query().order_by(order_by).paginate(*self._params.pagination)
for key, val in self._params.filters.dict(exclude_defaults=True, exclude_none=True).items():
query = query.where(getattr(self.MODEL, key).in_(val))
return list(query)
def _get_api_route_params(self) -> dict:
model = list_serializer(self.MODEL)
fields = tuple(field.safe_name for field in self.MODEL._meta.sorted_fields)
def data_dependency(
filters: model = Depends(),
sort_col: Literal[fields] = Query(self.MODEL._meta.primary_key.safe_name, title='Sort Column'),
sort_dir: Literal['asc', 'desc'] = Query('desc', title='Sort Direction'),
page: int = Query(default=1, ge=1),
per_page: int = Query(default=10, ge=1),
):
self._params = ListParams(
filters=filters,
sort=(sort_col,sort_dir),
pagination=(page,per_page)
)
params = super()._get_api_route_params()
params.update({
'dependencies': [Depends(data_dependency)],
})
return params
This allows filtering by one value as well as multiple values. NOTE: using multiple arguments for the same parameter will work like OR, not AND. example: ?text=test will return a list where text is 'test', ?text=test&text=test2 will return a list where text is 'test' OR 'test2'
here's a script to quickly test (and view the docs):
import uvicorn
import peewee as pw
from fastapi import FastAPI
DB = pw.SqliteDatabase('testdb')
class TestModel(pw.Model):
id = pw.AutoField()
text = pw.TextField()
number = pw.IntegerField(null=True)
class Meta:
database = DB
TestModel.create_table()
app = FastAPI()
ListFastAPIView.make_model_view(TestModel)().add_to_app(app)
uvicorn.run(app)