FastAPI Filter
fastapi-filter is a FastAPI extension that provides a flexible way to add filtering capabilities to your API endpoints. It integrates seamlessly with popular ORMs/ODMs like SQLAlchemy, MongoEngine, and Beanie. The current version is 2.0.1 and it maintains an active release cadence, frequently updating to support the latest versions of FastAPI, Pydantic, and its database backend dependencies.
Common errors
-
RuntimeError: 'MyFilterSchema' does not have a `model` defined in its `Constants` inner class.
cause The `model` attribute in your `Filter.Constants` inner class is either missing or incorrectly referencing your ORM/ODM model.fixEnsure your filter schema has `class Constants(Filter.Constants): model = YourORMModel` where `YourORMModel` is your SQLAlchemy, MongoEngine, or Beanie model. -
ModuleNotFoundError: No module named 'fastapi_filter.contrib.sqlalchemy' (or .mongoengine, .beanie)
cause You are trying to import a backend-specific `Filter` class, but the corresponding extra dependency for that backend was not installed.fixInstall the required extra: `pip install fastapi-filter[sqlalchemy]` (or `[mongoengine]`, `[beanie]`) depending on the backend you intend to use. -
Filter with `like` or `ilike` operators returns no results or unexpected results when using `fastapi-filter` v0.6.0 or later.
cause Since version 0.6.0, `fastapi-filter` no longer automatically adds the `%` wildcard character to `like` and `ilike` queries.fixManually add the wildcard character to your query string parameters. For example, for a filter `name__like='test'`, your query parameter should be `?name__like=%25test%25` (URL-encoded `%test%`).
Warnings
- breaking Python 3.8 support was dropped in `v2.0.0`.
- breaking `fastapi-filter` `v1.0.0` introduced breaking changes to support FastAPI >= 0.100.0 and Pydantic >= 2.0.0.
- breaking The behavior of `like` and `ilike` operators changed in `v0.6.0`. The wildcard character (`%`) is no longer automatically added by the filter.
- gotcha Filter `Constants` class requires the `model` attribute to be set to your ORM/ODM model.
Install
-
pip install fastapi-filter -
pip install fastapi-filter[sqlalchemy] -
pip install fastapi-filter[mongoengine] -
pip install fastapi-filter[beanie]
Imports
- FilterDepends
from fastapi_filter import FilterDepends
- Filter (for SQLAlchemy)
from fastapi_filter import Filter
from fastapi_filter.contrib.sqlalchemy import Filter
- Filter (for MongoEngine)
from fastapi_filter import Filter
from fastapi_filter.contrib.mongoengine import Filter
- Filter (for Beanie)
from fastapi_filter import Filter
from fastapi_filter.contrib.beanie import Filter
Quickstart
from fastapi import FastAPI, Depends
from typing import Optional
from pydantic import Field
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker, Session
from fastapi_filter.contrib.sqlalchemy import Filter, FilterDepends
# 1. Database setup (in-memory SQLite for example)
SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
description = Column(String)
Base.metadata.create_all(bind=engine)
# Dependency to get DB session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# 2. Define your Filter schema
class ItemFilter(Filter):
name: Optional[str] = Field(None, description="Filter by item name")
id__gt: Optional[int] = Field(None, alias="id_gt", description="Filter by ID greater than")
class Constants(Filter.Constants):
model = Item # Associate filter with your SQLAlchemy model
search_field_name = "name" # Example search field
# 3. FastAPI application
app = FastAPI()
@app.on_event("startup")
async def startup_event():
db = SessionLocal()
# Populate data if empty for demonstration
if not db.query(Item).first():
db.add(Item(name="First Item", description="Description of first item"))
db.add(Item(name="Second Item", description="Description of second item"))
db.commit()
db.close()
@app.get("/items/")
async def read_items(
item_filter: ItemFilter = FilterDepends(ItemFilter),
db: Session = Depends(get_db)
):
query = item_filter.filter(db.query(Item))
items = query.all()
return items
# To run this example:
# 1. pip install fastapi uvicorn sqlalchemy fastapi-filter[sqlalchemy]
# 2. Save the code as main.py
# 3. Run from your terminal: uvicorn main:app --reload
# 4. Access in browser/curl:
# http://127.0.0.1:8000/items/
# http://127.0.0.1:8000/items/?name=First%20Item
# http://127.0.0.1:8000/items/?id_gt=1