Reputation: 433
I'm working on creating dynamic filters using nested AND / OR logic, and would like to include NOT as an option. This leverages Q objects to create the nested AND / OR logic.
The class takes in a json object like so:
filters = {
'and': {
"url__is": "www.test.com",
"name__is": "test"
}
}
This gets compiled down to
.filter(Q(url__is='www.test.com') and Q(name__is='test')
This works via a recursive function that really just does this on each level of the json tree.
return source_queryset.filter(reduce(and_, filter_list))
and_ is from the python operator library and has been working great. I'd like to add NOT as an option as well though, and can't seem to find an equivalent option to reduce a list of Q objects to.
Does anyone know a way to use reduce in a way that creates the idea of not equal to a list of q objects?
Upvotes: 0
Views: 442
Reputation: 4264
You're looking for the ~
operator on a Q
object, which is a complex lookup.
In the end you would have something like this:
.filter(~Q(url__is='www.test.com'))
To match your recursive function you should use the inv
or invert
operator. Because it matches the desired output when using ~
operator.
>>> from django.db.models import Q
>>> from operator import inv
>>> ~Q()
<Q: (NOT (AND: ))>
>>> inv(Q())
<Q: (NOT (AND: ))>
So you can use it in your recursive function with something like this:
return source_queryset.filter(map(inv, filter_list))
Upvotes: 1
Reputation: 13731
You can flip any Q object by applying the ~
operator in front of it.
.exclude(Q(id=5))
is the same as:
.filter(~Q(id=5))
You should be able to use this when calculating filter_list
.
Upvotes: 0