Refactor exam search widget: streamline filtering logic and enhance queryset efficiency

This commit is contained in:
Ross
2026-02-16 13:49:17 +00:00
parent 6e30fcc19f
commit c61f92ae9e
2 changed files with 22 additions and 33 deletions
+22 -22
View File
@@ -6757,11 +6757,6 @@ def exam_search_widget(request):
qobj |= Q(**{lk: q})
qs = model.objects.filter(qobj)
# Limit results
limit = 50 if q in ("*", "%") else 10
qs = qs.order_by("name")[:limit]
# Apply optional filters from GET params to the per-model queryset
# Only include filters that were supplied in GET _and_ where the model
# actually exposes the field. This prevents models without a given
@@ -6777,26 +6772,31 @@ def exam_search_widget(request):
continue
extra_filters[pname] = val
# Apply filters at the queryset level for efficiency
if extra_filters:
try:
qs = qs.filter(**extra_filters)
except Exception:
# If a filter cannot be applied at DB level, fall back to leaving qs unchanged
pass
# Limit results (wildcard returns up to 50)
limit = 50 if q in ("*", "%") else 10
qs = qs.order_by("name")[:limit]
results = []
logger.error(f"Exam search widget: model={model}, q='{q}', extra_filters={extra_filters}, initial_count={qs.count() if qs is not None else 'N/A'}")
logger.error(f"Exam search widget: model={model}, q='{q}', extra_filters={extra_filters}, post_filter_count={qs.count() if qs is not None else 'N/A'}")
for e in qs:
# apply any extra_filters defensively (models may not have fields)
skip = False
for k, v in extra_filters.items():
if getattr(e, k, None) != v:
skip = True
break
if skip:
if not user_can_view_exam(e, request.user):
continue
if user_can_view_exam(e, request.user):
results.append({
"id": e.pk,
"text": str(e),
"archive": getattr(e, "archive", False),
"open_access": getattr(e, "open_access", False),
"exam_mode": getattr(e, "exam_mode", False),
"candidates_only": getattr(e, "candidates_only", False),
})
results.append({
"id": e.pk,
"text": str(e),
"archive": getattr(e, "archive", False),
"open_access": getattr(e, "open_access", False),
"exam_mode": getattr(e, "exam_mode", False),
"candidates_only": getattr(e, "candidates_only", False),
})
logger.error(f"Exam search widget: returning {len(results)} results after filtering")
-11
View File
@@ -564,17 +564,6 @@ class ExamSearchSelectMultipleWidget:
return {{ cleaned: cleaned, filters: filters }};
}}
function parseFilterTokens(q) {{
const filters = {{}};
if (!q) return {{ cleaned: '', filters: filters }};
let cleaned = q.replace(tokenRe, function(m, name, val) {{
filters[name] = /^(1|true|yes)$/i.test(val);
return ' ';
}});
cleaned = cleaned.replace(/\s+/g,' ').trim();
return {{ cleaned: cleaned, filters: filters }};
}}
function fetchResults(rawQ) {{
const parsed = parseFilterTokens(rawQ || '');
const q = parsed.cleaned;