Suppose I have a query method with serveral optional filters. What I want to achieve is, If I pass some not None value to filter parameters then do a filter, if filter value is None, then just ignore it.
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()
What I want to avoid is the pattern
if XXX:
res.filter(XXX=XXX)
I wonder if there is any more elegant way to achieve this?
For example, pass various filters as parameters?
Or maybe, we can do some magic to omit the filter when the filter value is None?
lazy = 'dynamic': When querying with lazy = 'dynamic', however, a separate query gets generated for the related object. If you use the same query as 'select', it will return: You can see that it returns a sqlalchemy object instead of the city objects.
The second one, filter_by(), may be used only for filtering by something specifically stated - a string or some number value. So it's usable only for category filtering, not for expression filtering. On the other hand filter() allows using comparison expressions (==, <, >, etc.)
all() method. The Query object, when asked to return full entities, will deduplicate entries based on primary key, meaning if the same primary key value would appear in the results more than once, only one object of that primary key would be present.
Using a SQL BETWEEN operator will evaluate ranges in an inclusive manner.
Code perfectly equivalent to the one you've shown is:
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()
I'm not quite sure why you need the named argument to res.filter
to be specifically filter1
, filter2
, etc, but this snippet will do it without the repetitious pattern that you understandably want to avoid.
Should the names not actually be filter1
, filter2
, etc, that's OK as long as the required names are known:
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()
This variant would work in this case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With