Sqlalchemy - элегантный способ борьбы с несколькими дополнительными фильтрами?

106
12

Предположим, что у меня есть метод запроса с серверными дополнительными фильтрами. Я хочу достичь: если я передаю некоторое значение None, чтобы фильтровать параметры, тогда сделайте фильтр, если значение фильтра равно None, а затем просто проигнорируйте его.


def get_query_results(filter1=None, filter2=None, ...):
res = models.Item.query
if filter1 is not None:
res = res.filter(filter1=filter1)
if filter2 is not None:
res = res.filter(filter2=filter2)
....
return res.all()

Чего я хочу избежать, это шаблон


if XXX:
res.filter(XXX=XXX)

Интересно, есть ли еще более элегантный способ достичь этого?


Например, передайте различные фильтры в качестве параметров?


Или, может быть, мы можем сделать магию, чтобы опустить фильтр, когда значение фильтра равно None?

спросил(а) 2021-01-19T17:33:35+03:00 2 месяца, 3 недели назад
1
Решение
87

Код, совершенно эквивалентный тому, который вы показали:


def get_query_results(*filters):
res = models.Item.query
for i, filt in enumerate(filters, 1):
if filt is not None:
d = {'filter{}'.format(i): filt}
res = res.filter(**d)
return res.all()

Я не совсем уверен, почему вам нужно, чтобы именованный аргумент res.filter был специально filter1, filter2 и т.д., но этот фрагмент будет делать это без повторяющегося шаблона, которого вы, по понятным причинам, хотите избежать.

Если имена не на самом деле являются filter1, filter2 и т.д., это нормально, пока известны требуемые имена:


NAMES = 'foo bar baz bat'.split()

def get_query_results(*filters):
res = models.Item.query
for name, filt in zip(NAMES, filters):
if filt is not None:
d = {name: filt}
res = res.filter(**d)
return res.all()


Этот вариант будет работать в этом случае.

ответил(а) 2021-01-19T17:33:35+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема