Reputation: 2199
I have a Django app where I need to combine two QuerySets, and disregard the exclude() filter only for certain items.
Here is an example of the model and the query.
class MyModel(models.Model):
name = models.CharField(max_length=20)
var1 = models.IntegerField()
var2 = models.BooleanField()
var3 = models.BooleanField()
var4 = models.IntegerField()
var5 = models.IntegerField()
qs1 = MyModel.objects.filter(var1__lte=10,var2=True).exclude(Q(var4=10) | Q(var5=20))
must_include_list = ['name1','name2','name3']
qs2 = MyModel.objects.filter(name__in=must_include_list)
I need to have a single queryset that does the filter and exclude from qs1, but also includes the rows from qs2 regardless of whether they match the qs1 filter and exclude.
I tried doing this:
qs1 = MyModel.objects.filter(Q(var1__lte=10,var2=True) | Q(name__in=must_include_list)).exclude(Q(var4=10| | Q(var5=20))
But it still applies the exclude to the must_include_list, so I miss some of the required entries.
Is there a way to tell the exclude() to not exclude the items in must_include_list, or is there a way to combine the two since querysets don't have an extend() method?
My solution based on bakkal's suggestion.
INCLUDE = Q(var1__lte=10,var2=True)
EXCLUDE = Q(var4=10) | Q(var5=20)
MUST_INCLUDE = Q(name__in=must_include_list)
FILTER = (INCLUDE & ~EXCLUDE) | MUST_INCLUDE
MyModel.objects.filter(FILTER).distinct()
Upvotes: 0
Views: 669
Reputation: 55448
Let's rewrite
MyModel.objects.filter(var1__lte=10,var2=True).exclude(Q(var4=10) | Q(var5=20))
As
X = Q(var1__lte=10, var2=True) & ~(Q(var4=10) | Q(var5=20))
MyModel.objects.filter(X)
The other query is simply
Y = Q(name__in=must_include_list)
Now what you want is X or Y so
MyModel.objects.filter(X | Y)
Tip: if you rename X and Y to meaningful names, your code will become readable and clean, and less cryptic than reading the nested filter/exclude and logic operators
Upvotes: 1