Skip to content

Commit 5390a4f

Browse files
fix: annotate conference list with has_errors, has_warnings, participants_count (#22)
* fix: annotate conference list with has_errors, has_warnings, participants_count After expand_fields was removed (PR #19), the conference list no longer includes participants or issues arrays. This broke the dashboard charts for error/warning icons and participant counts. Adds lightweight annotations via Exists() subqueries and Count() so the list includes: - has_errors (boolean) - has_warnings (boolean) - participants_count (integer) No N+1 queries — all computed in the same SQL query. * fix: use Subquery for participants_count to avoid filtered join bug Count('participants') reuses the filtered JOIN when participantId is in the query string, returning 1 instead of the real total. Switched to a Subquery that counts independently of the request's participant filter. Addresses review feedback from Codex and Alberto. * fix: exclude soft-deleted participants from participants_count The Subquery used Participant.objects.filter() which bypasses the is_active=True check, overcounting if any participants were soft-deleted.
1 parent a182209 commit 5390a4f

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

app/views/conference_view.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import datetime
22

33
from django.core.exceptions import ValidationError
4+
from django.db.models import Count, Exists, IntegerField, OuterRef, Subquery
45

56
from ..errors import (INVALID_PARAMETERS, CONFERENCE_NOT_FOUND,
67
MISSING_PARAMETERS, PMError)
78
from ..utils import JSONHttpResponse, serialize, paginate_and_serialize
89
from ..models.conference import Conference
10+
from ..models.issue import Issue
11+
from ..models.participant import Participant
912
from .generic_view import GenericView
1013

1114
class ConferencesView(GenericView):
@@ -40,12 +43,31 @@ def filter(cls, request):
4043
filters['created_at__gt'] = datetime.datetime.fromisoformat(filters.get('created_at__gt'))
4144

4245
try:
43-
objs = Conference.filter(**filters)
46+
objs = Conference.filter(**filters).annotate(
47+
has_errors=Exists(
48+
Issue.objects.filter(conference=OuterRef('pk'), type='e', is_active=True)
49+
),
50+
has_warnings=Exists(
51+
Issue.objects.filter(conference=OuterRef('pk'), type='w', is_active=True)
52+
),
53+
participants_count=Subquery(
54+
Participant.objects.filter(
55+
conferences=OuterRef('pk'),
56+
is_active=True,
57+
).order_by().values('conferences').annotate(
58+
cnt=Count('id', distinct=True)
59+
).values('cnt')[:1],
60+
output_field=IntegerField(),
61+
),
62+
)
4463
except ValidationError:
4564
raise PMError(status=400, app_error=INVALID_PARAMETERS)
4665

4766
return JSONHttpResponse(
48-
content=paginate_and_serialize(request, objs),
67+
content=paginate_and_serialize(
68+
request, objs,
69+
properties=['has_errors', 'has_warnings', 'participants_count'],
70+
),
4971
)
5072

5173
@classmethod

0 commit comments

Comments
 (0)