Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions examples/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import click
import uvicorn
from faker import Faker
from fastapi import Depends, FastAPI, Query
from pydantic import BaseModel, ConfigDict, Field
from fastapi import Depends, FastAPI
from pydantic import BaseModel, ConfigDict
from sqlalchemy import Column, ForeignKey, Integer, String, event, select
from sqlalchemy.engine import Engine
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
Expand Down Expand Up @@ -91,16 +91,15 @@ class Constants(Filter.Constants):

class UserFilter(Filter):
name: str | None = None
name__ilike: str | None = None
name__like: str | None = None
name__contains: str | None = None
name__icontains: str | None = None
name__neq: str | None = None
address: AddressFilter | None = FilterDepends(with_prefix("address", AddressFilter))
age__lt: int | None = None
age__gte: int = Field(Query(description="this is a nice description"))
"""Required field with a custom description.
age__gt: int | None = None
age__contains: str | None = None
age__icontains: str | None = None

See: https://github.com/tiangolo/fastapi/issues/4700 for why we need to wrap `Query` in `Field`.
"""
order_by: list[str] = ["age"]
search: str | None = None

Expand Down
15 changes: 11 additions & 4 deletions fastapi_filter_sqlalchemy/filter_sqlalchemy.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,22 @@ def _custom_filter_field(
:param field_name: Name of the filter field.
:return: Returns the query.
"""
# Делаем провреку, что такого поля нету в модели
# Если нету то вызываем метод get_field_name
# Передаем в него запрос и значение.
# We check that such a field does not exist in the models.
# If not, we call the get_field_name method.
# We pass the request and value to it.
if hasattr(self.Constants.model, field_name):
model_field = getattr(self.Constants.model, field_name)
if to_date:
model_field = func.date(model_field)
if operator != "likein" and operator != "between":
query = query.filter(getattr(model_field, operator)(value))
if (
operator in ("like", "ilike")
and not isinstance(model_field.type, String)
and isinstance(value, str)
):
query = query.filter(getattr(func.cast(model_field, String), operator)(value))
else:
query = query.filter(getattr(model_field, operator)(value))
elif operator == "between":
query = query.filter(getattr(model_field, operator)(*value))
else:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ignore_missing_imports = true

[tool.poetry]
name = "fastapi-filter-sqlalchemy"
version = "0.0.2"
version = "0.0.3"
description = "FastAPI filter SQLAlchemy"
authors = ["Sergey V. Elfimov <elfimovserg@gmail.com>"]
packages = [{include = "fastapi_filter_sqlalchemy"}]
Expand Down
2 changes: 2 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ class UserFilter(Filter): # type: ignore[misc, valid-type]
age__gte: int | None = None
age__in: list[int] | None = None
age__range: list[int] | None = None
age__contains: str | None = None
age__icontains: str | None = None
address: AddressFilter | None = FilterDepends( # type: ignore[valid-type]
with_prefix("address", AddressFilter), by_alias=True
)
Expand Down
4 changes: 4 additions & 0 deletions tests/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
[{"name__not": "Mr Praline", "age__gte": 21, "age__lt": 50}, 2],
[{"age__in": [1]}, 1],
[{"age__in": [21, 33]}, 3],
[{"age__icontains": "2"}, 2],
[{"age__contains": "21"}, 2],
[{"age__icontains": "150"}, 0],
[{"age__icontains": "1"}, 3],
[{"address": {"country__not_in": ["France"]}}, 3],
[{"age__in": "1"}, 1],
[{"age__in": "21,33"}, 3],
Expand Down
Loading