feat: migrate playevent_note to StringCriterion and add note string filter to SessionFilterBar

This commit is contained in:
2026-06-10 18:19:45 +02:00
parent a1304e19ad
commit 64392c3935
5 changed files with 33 additions and 38 deletions
+6 -23
View File
@@ -88,7 +88,7 @@ class GameFilter(OperatorFilter):
purchase_ownership_type: ChoiceCriterion | None = None # by ownership
# Cross-entity: substring match against the game's playevent notes
playevent_note: ChoiceCriterion | None = None
playevent_note: StringCriterion | None = None
# Free-text search (combines name + sort_name + platform name)
search: StringCriterion | None = None
@@ -407,30 +407,13 @@ class GameFilter(OperatorFilter):
return Q()
@staticmethod
def _playevent_note_to_q(criterion: ChoiceCriterion) -> Q:
"""Match games by substrings against their playevents' notes.
Each `value` entry is a substring OR'd into the include side; each
`excludes` entry is AND'd as a NOT. Empty lists contribute nothing.
"""
def _playevent_note_to_q(criterion: StringCriterion) -> Q:
"""Match games by substring / regex / null against their playevents' notes."""
from games.models import PlayEvent
q = Q()
if criterion.value:
include_q = Q()
negate_include = criterion.modifier == Modifier.EXCLUDES
for term in criterion.value:
matching_ids = PlayEvent.objects.filter(
note__icontains=term
).values_list("game_id", flat=True)
include_q |= Q(id__in=matching_ids)
q &= ~include_q if negate_include else include_q
for term in criterion.excludes:
matching_ids = PlayEvent.objects.filter(note__icontains=term).values_list(
"game_id", flat=True
)
q &= ~Q(id__in=matching_ids)
return q
event_q = criterion.to_q("note")
matching_ids = PlayEvent.objects.filter(event_q).values_list("game_id", flat=True)
return Q(id__in=matching_ids)
# ── SessionFilter ──────────────────────────────────────────────────────────
+3 -1
View File
@@ -105,7 +105,9 @@
{ name: "filter-price_currency", key: "price_currency" },
{ name: "filter-converted_currency", key: "converted_currency" },
{ name: "filter-name", key: "name" },
{ name: "filter-group", key: "group" }
{ name: "filter-group", key: "group" },
{ name: "filter-playevent_note", key: "playevent_note" },
{ name: "filter-note", key: "note" }
];
textFields.forEach(function (tf) {
var modifierEl = form.querySelector('[name="' + tf.name + '-modifier"]:checked');