Skip to main content

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


Download files

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

Source Distribution

sqlalchemy-filters-0.5.0.tar.gz (6.9 kB view details)

Uploaded Source

Built Distribution

sqlalchemy_filters-0.5.0-py2-none-any.whl (11.6 kB view details)

Uploaded Python 2

File details

Details for the file sqlalchemy-filters-0.5.0.tar.gz.

File metadata

File hashes

Hashes for sqlalchemy-filters-0.5.0.tar.gz
Algorithm Hash digest
SHA256 7ad69040caced71867601985ef707c2f316fefd252f7b2350e777241fd6c3de3
MD5 8b1beef15ee31d4f18e4256f48e50c01
BLAKE2b-256 ffb8257deca7abb298d68ae1e5c902495748140e68f3c4650e5dab5ab602934b

See more details on using hashes here.

File details

Details for the file sqlalchemy_filters-0.5.0-py2-none-any.whl.

File metadata

File hashes

Hashes for sqlalchemy_filters-0.5.0-py2-none-any.whl
Algorithm Hash digest
SHA256 244a0d3b914ac17b5016d0ee3106dc9c088cc398327a369fee35808aa9a3c4b6
MD5 b7be2776b255b98ccd489a5c000d28d3
BLAKE2b-256 4bf411988b4d7377ecbd7ddd12a8f42948f1c85148e1a90c3a9ed8a8f210f449

See more details on using hashes here.

Supported by

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