Refactor exam search widget: streamline filtering logic and enhance queryset efficiency
This commit is contained in:
+14
-14
@@ -6757,11 +6757,6 @@ def exam_search_widget(request):
|
|||||||
qobj |= Q(**{lk: q})
|
qobj |= Q(**{lk: q})
|
||||||
qs = model.objects.filter(qobj)
|
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
|
# Apply optional filters from GET params to the per-model queryset
|
||||||
# Only include filters that were supplied in GET _and_ where the model
|
# Only include filters that were supplied in GET _and_ where the model
|
||||||
# actually exposes the field. This prevents models without a given
|
# actually exposes the field. This prevents models without a given
|
||||||
@@ -6777,18 +6772,23 @@ def exam_search_widget(request):
|
|||||||
continue
|
continue
|
||||||
extra_filters[pname] = val
|
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 = []
|
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:
|
for e in qs:
|
||||||
# apply any extra_filters defensively (models may not have fields)
|
if not user_can_view_exam(e, request.user):
|
||||||
skip = False
|
|
||||||
for k, v in extra_filters.items():
|
|
||||||
if getattr(e, k, None) != v:
|
|
||||||
skip = True
|
|
||||||
break
|
|
||||||
if skip:
|
|
||||||
continue
|
continue
|
||||||
if user_can_view_exam(e, request.user):
|
|
||||||
results.append({
|
results.append({
|
||||||
"id": e.pk,
|
"id": e.pk,
|
||||||
"text": str(e),
|
"text": str(e),
|
||||||
|
|||||||
@@ -564,17 +564,6 @@ class ExamSearchSelectMultipleWidget:
|
|||||||
return {{ cleaned: cleaned, filters: filters }};
|
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) {{
|
function fetchResults(rawQ) {{
|
||||||
const parsed = parseFilterTokens(rawQ || '');
|
const parsed = parseFilterTokens(rawQ || '');
|
||||||
const q = parsed.cleaned;
|
const q = parsed.cleaned;
|
||||||
|
|||||||
Reference in New Issue
Block a user