Easy to use paginator for FastAPI
Currently, supports only encode/databases as database library and tested with SQlite and PostgreSQL.
- Simple FastAPI integration.
- Navigation with page numbers (With total page count returned on first page).
- Navigation from a specific row (since).
- Ordering result (On multiple columns).
- Filtering result using various SQL functions.
FastAPI Paginator is available on PyPI, so it can be installed like any other Python package.
Example with Pip:
pip install fastapi_paginator
To use it, you only need to create a fastapi_paginator.Paginator
instance linked to
the database and routes
using fastapi_paginator.PageParameters
and fastapi_paginator.Page
.
import databases
import fastapi
import pydantic
import sqlalchemy
import fastapi_paginator
# Already existing database, FastAPI application, "item" table, and "item" model
database = databases.Database(f"sqlite:///local.db}")
app = fastapi.FastAPI()
table = sqlalchemy.Table(
"table",
sqlalchemy.MetaData(),
Column("id", sqlalchemy.Integer, primary_key=True),
Column("name", sqlalchemy.String, nullable=False),
)
class Item(pydantic.BaseModel):
"""Item in database."""
class Config:
"""Config."""
orm_mode = True # Required
id: int
name: str
# Create a paginator for the database (Required only once per database)
paginator = fastapi_paginator.Paginator(database)
# Create a paginated route
@app.get("/list")
async def list_data(
page_parameters: fastapi_paginator.PageParameters = Depends(),
) -> fastapi_paginator.Page[Item]:
"""List data with pagination."""
return await paginator(table.select(), Item, page_parameters)
Paginator parameters are passed as query parameters, for instance:
GET /list?order_by=id&page=2
The page to return.
When page is not specified or equal to 1
, the request returns total_page
that is
the maximum number of pages.
Cannot be used with since
.
The item from where starting to return the result.
When navigating between successive pages, the next_since
returned value should be used
as since
for the subsequent requests.
Cannot be used with page
.
Cannot be used with order_by
if not ordering on the field used by since
.
Sort the resulting items by the specified field name.
Order is descending if -
is added before the field name, else order is ascending.
This query parameter can be specified multiple time to sort by multiple columns.
Example:
"Ordering descending by the created_at
column: order_by=-created_at
Filter the resulting items.
The query must be in the form field_name operator argument
, with:
field_name
: the name on the field on where apply the filter.operator
: one operator from the list bellow.argument
: is the operator argument, it can be one or more value separated by,
(Depending on the operator), valid values must be a primitive JSON type like numbers, double-quoted strings,true
,false
andnull
.
This query parameter can be specified multiple time to filter on more criteria (Using AND logical conjunction).
Available operators:
=
: Equal to a single value (Also supportsnull
,true
andfalse
)<
: Lower than a single value.<=
: Lower or equal than a single value.>
: Greater than a single value.>=
: Greater or equal than a single value.between
: Between a pair of values (value_1
<=field_value
<=value_2
).in
: Present in a list of one or more values.like
: Like a single value (%
can be used as wildcard for zero to multiple characters,_
as wildcard for a single character,/
can be used as escape character for%
and_
).ilike
: Same aslike
, but case insensitive.startswith
: String representation starts with a single value.endswith
: String representation ends with a single value.contains
: String representation contains a single value.
Any operator can be negated by adding !
in front of it.
Warning: Depending on your HTTP client, the query parameter value may require to be URL encoded.
Example:
Returning only data with a name
field that does not start with
Product
: filter_by=name%20%21like%20%22Product%25%22
(With URL encoded value of: name !like "Product%"
')
The response is a JSON dictionnary with the following fields:
items
: The list returned items.next_since
: Next value to use withsince
query parameter.next_page
: Next value to use withpage
query parameter.total_pages
: Total pages, only computed and returned when on page 1
It is possible to override the json.loads
function used in all paginator as follows
(Example with orjson):
import orjson
import fastapi_paginator
fastapi_paginator.Paginator.json_loads = orjson.loads