Fix exclude-only multi filters matching nothing
MultiCriterion.to_q (used by SessionFilter for game/device) unconditionally added field__in=value even when value was empty, and __in=[] matches no rows — so a filter with only excludes (e.g. device excludes 11, no game/device includes) returned zero results. Guard the empty value like ChoiceCriterion already does, so an exclude-only criterion means 'all rows except the excluded ids'. https://claude.ai/code/session_01XzhXvMvw42CQGc9kmin3GS
This commit is contained in:
+3
-1
@@ -277,7 +277,9 @@ class MultiCriterion(_Criterion):
|
|||||||
def to_q(self, field_name: str) -> Q:
|
def to_q(self, field_name: str) -> Q:
|
||||||
m = self.modifier
|
m = self.modifier
|
||||||
if m == Modifier.INCLUDES:
|
if m == Modifier.INCLUDES:
|
||||||
q = Q(**{f"{field_name}__in": self.value})
|
q = Q()
|
||||||
|
if self.value:
|
||||||
|
q &= Q(**{f"{field_name}__in": self.value})
|
||||||
if self.excludes:
|
if self.excludes:
|
||||||
q &= ~Q(**{f"{field_name}__in": self.excludes})
|
q &= ~Q(**{f"{field_name}__in": self.excludes})
|
||||||
return q
|
return q
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from common.criteria import (
|
|||||||
ChoiceCriterion,
|
ChoiceCriterion,
|
||||||
IntCriterion,
|
IntCriterion,
|
||||||
Modifier,
|
Modifier,
|
||||||
|
MultiCriterion,
|
||||||
StringCriterion,
|
StringCriterion,
|
||||||
)
|
)
|
||||||
from common.components import FilterBar
|
from common.components import FilterBar
|
||||||
@@ -98,6 +99,29 @@ class TestChoiceCriterion:
|
|||||||
assert c.to_q("status") == ~Q(status__in=["f"])
|
assert c.to_q("status") == ~Q(status__in=["f"])
|
||||||
|
|
||||||
|
|
||||||
|
class TestMultiCriterion:
|
||||||
|
def test_includes(self):
|
||||||
|
c = MultiCriterion(value=[797], modifier=Modifier.INCLUDES)
|
||||||
|
assert c.to_q("game_id") == Q(game_id__in=[797])
|
||||||
|
|
||||||
|
def test_excludes_only_empty_value(self):
|
||||||
|
"""Exclude one device with no includes — value=[], excludes=[11].
|
||||||
|
|
||||||
|
Regression: an empty ``value`` must not add ``__in=[]`` (which matches
|
||||||
|
nothing); the criterion should mean "all rows except device 11".
|
||||||
|
"""
|
||||||
|
c = MultiCriterion(value=[], excludes=[11], modifier=Modifier.INCLUDES)
|
||||||
|
assert c.to_q("device_id") == ~Q(device_id__in=[11])
|
||||||
|
|
||||||
|
def test_include_and_exclude(self):
|
||||||
|
c = MultiCriterion(value=[1], excludes=[2], modifier=Modifier.INCLUDES)
|
||||||
|
assert c.to_q("game_id") == Q(game_id__in=[1]) & ~Q(game_id__in=[2])
|
||||||
|
|
||||||
|
def test_is_null(self):
|
||||||
|
c = MultiCriterion(value=[], modifier=Modifier.IS_NULL)
|
||||||
|
assert c.to_q("device_id") == Q(device_id__isnull=True)
|
||||||
|
|
||||||
|
|
||||||
class TestChoiceCriterionAgainstDB:
|
class TestChoiceCriterionAgainstDB:
|
||||||
"""Verify ChoiceCriterion produces correct DB results."""
|
"""Verify ChoiceCriterion produces correct DB results."""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user