This repository was developed to provide a simple JSON format interface to the SQLAlchemy
query API to query on json SQL fields, which can be used by front-end applications to generate automatically SQL filtering queries
with minimum effort in the back-end service implementation.
Some of the sqlalchemy-filtering utility features include:
| Category | Feature | PostgreSQL | MySQL | SQLite |
|---|---|---|---|---|
| Filtering | Ability to filter simple SQL fields | Yes | Yes | Yes |
Ability to filter json SQL fields |
Yes | Yes (Beta) | No | |
| Ability to filter join queries | No | No | No | |
| Sorting | Ability to sort simple SQL fields | Yes | Yes | Yes |
Ability to sort json SQL fields |
Yes | Yes (Beta) | No | |
| Ability to sort on joined fields | No | No | No |
Given the following SQLAlchemy models:
from sqlalchemy import Column, Integer, String, DateTime, Float
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import functions
Base = declarative_base()
class UserInfo(Base):
__tablename__ = "user_info"
id = Column(Integer, primary_key=True, index=True)
details = Column(JSONB)
creation_date = Column(DateTime, nullable=False, server_default=functions.now())
class Ratings(Base):
__tablename__ = "ratings"
id = Column(Integer, primary_key=True, index=True)
creation_date = Column(DateTime, nullable=False, server_default=functions.now())
movie_name = Column(String)
rating = Column(Float)from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from tests import models
engine = create_engine(
'postgresql://postgres:password@localhost:5432/filter'
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db = SessionLocal()
query = db.query(models.UserInfo)Assuming we have records in the database with the following structure:
- ID:
id(type: integer) - Details:
details(type: json)
{
"skin": "White",
"extra": {
"test": "value"
},
"gender": "Male",
"height": 188,
"last_name": "Walker",
"first_name": "Paul",
"user_details": [
{
"skill": "Fighting",
"rating": 7
},
{
"skill": "Driving",
"rating": 10
}
]
}- Creation date:
creation_date(type: timestamp)
# Case 1: Flat request on JSON column
obj = {
"filter": [
{
## (PostgreSQL) It returns all users that have skill 'Fighting' with rating 10
"field": "details",
"node": "user_details",
"operator": "@>",
"value": "[{\"skill\":\"Fighting\",\"rating\":10}]",
},
{
## (PostgreSQL) It returns all users that have skill 'Fighting' and any rating (in any skill) with rating 10
"field": "details",
"node": "user_details",
"operator": "@>",
"value": "[{\"skill\":\"Fighting\"},{\"rating\":10}]",
}
]
}# Case2: Nested request in JSON nodes
obj = {
"filter": [
{
"field": "details",
"node": "extra",
"value": {
"field": "test",
"operator": "==",
"value": "value"
}
}
]
}from sqlalchemy_filtering.filter_util import filter_apply
from sqlalchemy_filtering.operators import SQLDialect
from sqlalchemy_filtering.validators import FilterRequest
from tests import models
query = filter_apply(query=query, entity=models.UserInfo, obj=FilterRequest(obj), dialect=SQLDialect.POSTGRESQL)Filtering operators AND (and_), OR (or_) and NOT (not_) are supported and can be used all together.
obj3 = {
"filter": {
"not": [
{
"field": "movie_name",
"operator": "==",
"value": "The Dark Knight"
},
{
"field": "rating",
"operator": "==",
"value": 7
}
]
}
}# Case 1: Sort request on JSON column
obj = {
"sort": [
{
"field": "details",
"node": "height",
"direction": "desc",
"nullsLast": True
}
]
}# Case 2: Sort request on inner JSON node column
obj = {
"sort": [
{
"field": "details",
"node": "extra.test",
"direction": "desc",
"nullsLast": True
}
]
}# Case 3: Sort request on simple column
obj = {
"sort": [
{
"field": "creation_date",
"direction": "desc",
"nullsLast": True
}
]
}from sqlalchemy_filtering.sort_util import sort_apply
from sqlalchemy_filtering.validators import SortRequest
from tests import models
query = sort_apply(query=query, entity=models.UserInfo, obj=SortRequest(obj))The list of the available comparison operators can be found below:
is(aliases:==,eq)is_not(aliases:!=,ne)is_nullis_not_null>(alias:gt)<(alias:lt)>=(alias:ge)<=(alias:le)likenot_likeilikenot_ilikeinnot_incontainsanymatchstarts_with
@><@@?@@
| System | Version |
|---|---|
| PostgreSQL | 9.2, 12.7 |
| MySQL | 8.0.20, 8.0.27 |
| SQLite | 3.37 |
| SQLAlchemy | >= 1.4.0 |
This Python project is available in the PyPi package index and can be installed using pip.
pip install sqlalchemy-filtering==0.1.2