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_paginatorTo 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=2The 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,falseandnull.
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,trueandfalse)<: 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 withsincequery parameter.next_page: Next value to use withpagequery 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