What I’m trying to do:
Use q.any_of to filter based on a multiple linking field, to restrict results to rows that have one of a set of linked rows.
There are a number of forum posts about this, and the general answer seems to be that you have to put each filter item in a list of its own. Without that you get a q.all_of effect.
But putting each filter item into a list of its own also doesn’t return the expected results. Regardless of which filter items are chosen, it returns any row that has a non-None entry for the multiple linking field.
Should q.any_of work the way I and others have tried to use it?
Note that I know I can filter in Python using a list comprehension. The point of this post isn’t to solve the general problem of filtering, but the specific problem of using q.any_of on multiple linking fields.
What I’ve tried and what’s not working:
@anvil.server.callable
def get_posts(filters):
# This fails to filter on the multiple link field correctly
if filters:
temp = [[r] for r in filters]
return app_tables.posts.search(universities=q.any_of(temp))
return app_tables.posts.search()
Clone link:
https://anvil.works/build#clone:3C4Z6A6P32QFVHNS=ASPO3LMOUCOH3ZWBNUYF2G37
1 Like
You need to unpack the items in your list:
q.any_of(*temp)
1 Like
I’d tried that at one point, it generates this error:
anvil.tables.TableError: Column 'universities' can only be searched with a List of rows from 'Universities' table (not a Row from 'Universities' table) in table 'Posts'
I’d need to see more of your code to be certain, but I don’t understand what your list comprehension does. Why not just unpack filters
in your any_of
call?
You can check out the clone link, everything’s there.
The docs say that a multiple linking field must be passed a list, so if I were to want to search for a single value it’d be universities=[rowfromuniversitytable]
.
Given that, it makes sense that a q.any_of would be something along the lines of q.any_of([row1], [row2], [row3])
. That’s what the list comprehension does, putting each filter row into a list of its own.
But the version where I unpack temp to create that sort of query, q.any_of(*temp)
gives the error I posted above, so that isn’t right.
Passing in a single list of lists as shown in the original post also doesn’t work. That somehow filters on non-empty fields.
Unpacking filters directly, q.any_of(filters)
does an AND on the filters, not an OR.
At this point, I don’t know if using q.any_of
on a multiple linking field should work, and I’m just not doing it right or there’s a bug, or if it shouldn’t work at all.
I’m not sure it’s the perfect solution but you could do something like this:
from itertools import combinations
def get_all_combs(iterable: list):
for i in range(1, len(iterable) + 1):
yield from combinations(iterable, i)
@anvil.server.callable
def get_posts(filters: list):
if filters:
temp = get_all_combs(filters)
return app_tables.posts.search(universities=q.any_of(*temp))
That does seem to work, thanks!
Ok my last post didn’t quite get the intention here, but I think I figured out the right way to approach this. You need to pass the list of selected items as *args
:
# in server
@anvil.server.callable
def get_posts(universities):
if len(universities) > 0:
return app_tables.posts.search(universities=q.any_of(*[[r] for r in universities]))
else:
return app_tables.posts.search()
# in form
def universities_change(self, **event_args):
self.repeating_panel_1.items = anvil.server.call('get_posts', self.universities.selected)
2 Likes
It looks like something has changed in Anvil very recently. Owen suggested doing that yesterday, and when I tried it the exception about six posts up was thrown.
Today, though, it works as expected, which is great!
2 Likes