Skip to main content

FastAPI filters with standard query parameter syntax (comma-separated values)

Project description

logo

license test codecov downloads pypi black

Introduction

fastapi_filters_standard is a fork of fastapi-filters providing filtering and sorting features for FastAPI applications.

This fork introduces standard query parameter syntax for filters:

  • Field operations are now standardized:

    field__operation
    

    Instead of the old syntax:

    field[operation]
    
  • Operations are standardized across the package, independent of SQLAlchemy naming.

  • For filters requiring lists, values are comma-separated in a single parameter:

    GET /places?main_industry=1,2,3
    
  • Optionally, Raw Mode can be used to receive filters exactly as sent in query parameters.

  • Nested filters are now supported, allowing filtering on related objects using syntax like state__fa_name__icontains=تهران.


Installation

pip install fastapi_filters_standard

Quickstart

Filters can be defined either manually or automatically from Pydantic models.

from typing import List

from fastapi import FastAPI, Depends
from pydantic import BaseModel, Field

from fastapi_filters_standard import (
    create_filters,
    create_filters_from_model,
    create_sorting_from_model,
    FilterValues,
    RawFilterValues,
    SortingValues,
)

app = FastAPI()


class UserOut(BaseModel):
    name: str = Field(..., example="Steve")
    surname: str = Field(..., example="Rogers")
    age: int = Field(..., example=102)


# Manual filters
@app.get("/users/manual")
async def get_users_manual_filters(
    filters: FilterValues = Depends(create_filters(name=str, surname=str, age=int)),
) -> List[UserOut]:
    pass


# Automatic filters from Pydantic model
@app.get("/users/auto")
async def get_users_auto_filters(
    filters: FilterValues = Depends(create_filters_from_model(UserOut)),
) -> List[UserOut]:
    pass


# Raw Mode example
@app.get("/users/raw")
async def get_users_raw_filters(
    filters: RawFilterValues = Depends(
        create_filters_from_model(UserOut, raw_mode=True)
    ),
) -> RawFilterValues:
    pass

Nested Filters Example

from fastapi import FastAPI, Depends
from pydantic import BaseModel
from sqlalchemy import select

from db.models import City
from fastapi_filters_standard import create_filters_from_model, FilterValues
from fastapi_filters_standard.ext.sqlalchemy import apply_filters

app = FastAPI()


class StateRead(BaseModel):
    fa_name: str


class CityRead(BaseModel):
    id: int
    fa_name: str
    state: StateRead


@app.get("/cities")
async def list_cities(
        filters: FilterValues = Depends(
            create_filters_from_model(
                CityRead,
                nested=True,
                max_depth=1,  # allow filtering one level deep (City -> State)
            )
        ),
):
    """
    Example usage:
    GET /cities?state__fa_name__icontains=تهران

    This produces:
    filters = {'state__fa_name': {'icontains': 'تهران'}}
    """
    query = apply_filters(select(City), filters, model=City)
    result = await db.scalars(query)
    return result.all()

This allows filtering cities based on fields of the related state object.


Nested Sorting Example

class FastAPI: pass

from fastapi import FastAPI, Depends
from pydantic import BaseModel
from sqlalchemy import select

from db.models import City
from fastapi_filters_standard import (
    SortingValues,
    create_sorting_from_model,
)
from fastapi_filters_standard.ext.sqlalchemy import apply_sorting

app = FastAPI()


class StateRead(BaseModel):
    fa_name: str


class CityRead(BaseModel):
    id: int
    fa_name: str
    state: StateRead


@app.get("/cities")
async def list_cities(
    sorting: SortingValues = Depends(
        create_sorting_from_model(
            CityRead,
            nested=True,
            max_depth=1,
        )
    ),
):
    """
    Example usage:

    GET /cities?sort=+state__fa_name,-fa_name
    """

    query = apply_sorting(
        select(City),
        sorting,
        model=City,
        nested=True,
    )

    result = await db.scalars(query)
    return result.all()

This allows ordering by fields of related models using the same double-underscore syntax as nested filters.

Examples:

GET /cities?sort=+state__fa_name
GET /cities?sort=-state__fa_name,+fa_name
GET /cities?sort=+country__name,-state__fa_name,+created_at

SQLAlchemy Integration

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi_filters_standard.ext.sqlalchemy import apply_filters

@app.get("/users")
async def get_users(
    db: AsyncSession = Depends(get_db),
    filters: FilterValues = Depends(create_filters_from_model(UserOut)),
) -> List[UserOut]:
    query = apply_filters(select(User), filters)
    result = await db.scalars(query)
    return result.all()

Raw Mode Example with pytest

import pytest
from fastapi import FastAPI, Depends
from fastapi.testclient import TestClient
from pydantic import BaseModel

from fastapi_filters_standard import create_filters_from_model, RawFilterValues


@pytest.mark.asyncio
async def test_raw_mode():
    app = FastAPI()

    class UserModel(BaseModel):
        username: str
        age: int

    @app.get("/")
    async def route(
            filters: RawFilterValues = Depends(create_filters_from_model(UserModel, raw_mode=True))
    ) -> RawFilterValues:
        return filters

    client = TestClient(app)
    res = client.get("/", params={"username__contains": "09001", "age__gte": "18"})

    assert res.status_code == 200
    assert res.json() == {"username__contains": "09001", "age__gte": "18"}

Features of this fork

  • Standardized query parameter syntax (field__operation)

  • Standardized operation names

  • Comma-separated list support for multi-value filters

  • Full support for filtering and sorting

    • Nested filters and sorting are supported, allowing filtering and ordering on related objects.

    Examples:

    GET /cities?state__fa_name__icontains=تهران
    GET /cities?sort=+state__fa_name,-country__name
    
  • Raw Mode: receive filters exactly as sent, for forwarding to external services

  • Compatible with FastAPI and SQLAlchemy async

  • Backwards compatible with most fastapi-filters features

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_filters_standard-0.7.0.tar.gz (104.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_filters_standard-0.7.0-py3-none-any.whl (28.7 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_filters_standard-0.7.0.tar.gz.

File metadata

  • Download URL: fastapi_filters_standard-0.7.0.tar.gz
  • Upload date:
  • Size: 104.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for fastapi_filters_standard-0.7.0.tar.gz
Algorithm Hash digest
SHA256 98a9aa5069a794f14f9089b3bc9b5262775f445e34c0ff58a5e57dba78a12400
MD5 0c0a1d8bfafcd427e4949bf7cb678e61
BLAKE2b-256 3295625843621259f8309285909a6cf1d7dec87b331031a5defa6c7935c8694e

See more details on using hashes here.

File details

Details for the file fastapi_filters_standard-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_filters_standard-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d7221c694bddd10610fea33db1172c10bf0327f92d6351e665b676b444e84284
MD5 7272ba3169af5b107ba3c2c97ee2a881
BLAKE2b-256 1cfc972d59f3f8558789c365a284c6737a104dfd10ed37499f3e6e66a9f8f1f8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page