A library to filter SQLAlchemy queries.
Project description
Filter, sort and paginate SQLAlchemy query objects. Ideal for exposing these actions over a REST API.
Filtering
Assuming that we have a SQLAlchemy query object:
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
class Base(object):
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
count = Column(Integer, nullable=True)
Base = declarative_base(cls=Base)
class Foo(Base):
__tablename__ = 'foo'
# ...
query = session.query(Foo)
Then we can apply filters to that query object (multiple times):
from sqlalchemy_filters import apply_filters
# `query` should be a SQLAlchemy query object
filters = [{'field': 'name', 'op': '==', 'value': 'name_1'}]
filtered_query = apply_filters(query, filters)
more_filters = [{'field': 'foo_id', 'op': 'is_not_null'}]
filtered_query = apply_filters(filtered_query, more_filters)
result = filtered_query.all()
It is also possible to filter queries that contain multiple models, including joins:
class Bar(Base):
__tablename__ = 'bar'
foo_id = Column(Integer, ForeignKey('foo.id'))
query = session.query(Foo).join(Bar)
filters = [
{'model': 'Foo', field': 'name', 'op': '==', 'value': 'name_1'},
{'model': 'Bar', field': 'count', 'op': '>=', 'value': 5},
]
filtered_query = apply_filters(query, filters)
result = filtered_query.all()
You must specify the model key in each filter if the query is against more than one model.
Note that we can also apply filters to queries defined by fields or functions:
query_alt_1 = session.query(Foo.id, Foo.name)
query_alt_2 = session.query(func.count(Foo.id))
Sort
from sqlalchemy_filters import apply_sort
# `query` should be a SQLAlchemy query object
order_by = [
{'model': 'Foo', field': 'name', 'direction': 'asc'},
{'model': 'Bar', field': 'id', 'direction': 'desc'},
]
sorted_query = apply_sort(query, order_by)
result = sorted_query.all()
Pagination
from sqlalchemy_filters import apply_pagination
# `query` should be a SQLAlchemy query object
query, pagination = apply_pagination(query, page_number=1, page_size=10)
page_size, page_number, num_pages, total_results = pagination
assert 10 == len(query)
assert 10 == page_size == pagination.page_size
assert 1 == page_number == pagination.page_number
assert 3 == num_pages == pagination.num_pages
assert 22 == total_results == pagination.total_results
Filters format
Filters must be provided in a list and will be applied sequentially. Each filter will be a dictionary element in that list, using the following format:
filters = [
{'model': 'model_name', 'field': 'field_name', 'op': '==', 'value': 'field_value'},
{{'model': 'model_name', 'field': 'field_2_name', 'op': '!=', 'value': 'field_2_value'},
# ...
]
The model key is optional if the query being filtered only applies to one model.
If there is only one filter, the containing list may be omitted:
filters = {'field': 'field_name', 'op': '==', 'value': 'field_value'}
Where field is the name of the field that will be filtered using the operator provided in op (optional, defaults to ==) and the provided value (optional, depending on the operator).
This is the list of operators that can be used:
is_null
is_not_null
==, eq
!=, ne
>, gt
<, lt
>=, ge
<=, le
like
in
not_in
Boolean Functions
and, or, and not functions can be used and nested within the filter definition:
filters = [
{
'or': [
{
'and': [
{'field': 'field_name', 'op': '==', 'value': 'field_value'},
{'field': 'field_2_name', 'op': '!=', 'value': 'field_2_value'},
]
},
{
'not': [
{'field': 'field_3_name', 'op': '==', 'value': 'field_3_value'}
]
},
],
}
]
Note: or and and must reference a list of at least one element. not must reference a list of exactly one element.
Sort format
Sort elements must be provided as dictionaries in a list and will be applied sequentially:
order_by = [
{'model': 'Foo', 'field': 'name', 'direction': 'asc'},
{'model': 'Bar', field': 'id', 'direction': 'desc'},
# ...
]
Where field is the name of the field that will be sorted using the provided direction.
The model key is optional if the query being sorted only applies to one model.
Running tests
There are some Makefile targets that can be used to run the tests. A test database will be created, used during the tests and destroyed afterwards.
The default configuration uses both SQLite and MySQL (if the driver is installed) to run the tests, with the following URIs:
sqlite+pysqlite:///test_sqlalchemy_filters.db
mysql+mysqlconnector://root:@localhost:3306/test_sqlalchemy_filters
Example of usage:
$ # using default settings
$ make test
$ make coverage
$ # overriding DB parameters
$ ARGS='--mysql-test-db-uri mysql+mysqlconnector://root:@192.168.99.100:3340/test_sqlalchemy_filters' make test
$ ARGS='--sqlite-test-db-uri sqlite+pysqlite:///test_sqlalchemy_filters.db' make test
$ ARGS='--mysql-test-db-uri mysql+mysqlconnector://root:@192.168.99.100:3340/test_sqlalchemy_filters' make coverage
$ ARGS='--sqlite-test-db-uri sqlite+pysqlite:///test_sqlalchemy_filters.db' make coverage
License
Apache 2.0. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file sqlalchemy-filters-0.5.0.tar.gz
.
File metadata
- Download URL: sqlalchemy-filters-0.5.0.tar.gz
- Upload date:
- Size: 6.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7ad69040caced71867601985ef707c2f316fefd252f7b2350e777241fd6c3de3 |
|
MD5 | 8b1beef15ee31d4f18e4256f48e50c01 |
|
BLAKE2b-256 | ffb8257deca7abb298d68ae1e5c902495748140e68f3c4650e5dab5ab602934b |
File details
Details for the file sqlalchemy_filters-0.5.0-py2-none-any.whl
.
File metadata
- Download URL: sqlalchemy_filters-0.5.0-py2-none-any.whl
- Upload date:
- Size: 11.6 kB
- Tags: Python 2
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 244a0d3b914ac17b5016d0ee3106dc9c088cc398327a369fee35808aa9a3c4b6 |
|
MD5 | b7be2776b255b98ccd489a5c000d28d3 |
|
BLAKE2b-256 | 4bf411988b4d7377ecbd7ddd12a8f42948f1c85148e1a90c3a9ed8a8f210f449 |