Skip to content

Commit 2389faf

Browse files
committed
optimize CatalogueView with improved query efficiency and filtering
1 parent 02ca14b commit 2389faf

File tree

2 files changed

+83
-42
lines changed

2 files changed

+83
-42
lines changed

src/api/serializers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class AuthorHistorySerializer(serializers.ModelSerializer):
7979
author = serializers.PrimaryKeyRelatedField(
8080
queryset=Author.objects.all(), write_only=True
8181
)
82+
area_name = serializers.CharField(source="area.name", read_only=True, default=None)
8283

8384
class Meta:
8485
model = AuthorHistory
@@ -87,6 +88,7 @@ class Meta:
8788
"author",
8889
"party",
8990
"area",
91+
"area_name",
9092
"exec_posts",
9193
"service_posts",
9294
"start_date",

src/api/views.py

Lines changed: 81 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ def get(self, request) -> JsonResponse:
459459
460460
Query Parameters:
461461
house: 0 for Dewan Rakyat, 1 for Dewan Negara
462+
dropdown: If present, only returns the structure without sitting details
463+
term: Filter by specific term (optional)
462464
463465
Response Format:
464466
{
@@ -485,71 +487,108 @@ def get(self, request) -> JsonResponse:
485487
...
486488
},
487489
...
488-
}
490+
},
491+
"total_count": <total_count>
489492
}
490493
"""
491494
# get query parameters, default DR
492495
house_type = request.GET.get("house", "dewan-rakyat")
496+
house_int = ParliamentaryCycle.get_integer_value(house_type)
497+
498+
# Filter parameters (optional)
499+
term_filter = request.GET.get("term")
493500

494-
# for dropdown menu
501+
# For dropdown menu
495502
is_dropdown = request.GET.get("dropdown", None)
496503

497-
# filter Sitting model based on query parameters
498-
sittings = Sitting.objects.filter(
499-
cycle__house=ParliamentaryCycle.get_integer_value(house_type)
500-
).order_by("date")
504+
# Start with base query
505+
cycles_query = ParliamentaryCycle.objects.filter(house=house_int)
501506

502-
# build nested term -> session -> meeting structure
503-
cycles = ParliamentaryCycle.objects.filter(
504-
house=ParliamentaryCycle.get_integer_value(house_type)
505-
)
506-
terms = cycles.values("term").annotate(
507+
# Apply term filter if provided
508+
if term_filter:
509+
cycles_query = cycles_query.filter(term=term_filter)
510+
511+
# Build nested term -> session -> meeting structure more efficiently
512+
terms = cycles_query.values("term").annotate(
507513
start_date=Min("start_date"),
508514
end_date=Max("end_date"),
509515
)
510-
cycle_map = {
511-
term["term"]: {
516+
517+
cycle_map = {}
518+
for term in terms:
519+
term_id = term["term"]
520+
cycle_map[term_id] = {
512521
"start_date": term["start_date"],
513522
"end_date": term["end_date"],
514523
}
515-
for term in terms
516-
}
517524

518-
sessions = cycles.values("term", "session").annotate(
519-
start_date=Min("start_date"),
520-
end_date=Max("end_date"),
521-
)
522-
for session in sessions:
523-
cycle_map[session["term"]][session["session"]] = {
524-
"start_date": session["start_date"],
525-
"end_date": session["end_date"],
526-
}
525+
# Get sessions for this term
526+
sessions = (
527+
cycles_query.filter(term=term_id)
528+
.values("session")
529+
.annotate(
530+
start_date=Min("start_date"),
531+
end_date=Max("end_date"),
532+
)
533+
)
527534

528-
meetings = cycles.values("term", "session", "meeting").annotate(
529-
start_date=Min("start_date"),
530-
end_date=Max("end_date"),
531-
)
532-
for meeting in meetings:
533-
cycle_map[meeting["term"]][meeting["session"]][meeting["meeting"]] = {
534-
"start_date": meeting["start_date"],
535-
"end_date": meeting["end_date"],
536-
}
537-
if not is_dropdown:
538-
cycle_map[meeting["term"]][meeting["session"]][meeting["meeting"]][
539-
"sitting_list"
540-
] = []
535+
for session in sessions:
536+
session_id = session["session"]
537+
cycle_map[term_id][session_id] = {
538+
"start_date": session["start_date"],
539+
"end_date": session["end_date"],
540+
}
541+
542+
# Get meetings for this session
543+
meetings = (
544+
cycles_query.filter(term=term_id, session=session_id)
545+
.values("meeting")
546+
.annotate(
547+
start_date=Min("start_date"),
548+
end_date=Max("end_date"),
549+
)
550+
)
551+
552+
for meeting in meetings:
553+
meeting_id = meeting["meeting"]
554+
cycle_map[term_id][session_id][meeting_id] = {
555+
"start_date": meeting["start_date"],
556+
"end_date": meeting["end_date"],
557+
}
558+
if not is_dropdown:
559+
cycle_map[term_id][session_id][meeting_id]["sitting_list"] = []
560+
561+
# Get all sittings for this house
562+
sittings_query = Sitting.objects.filter(cycle__house=house_int)
541563

542-
data = {"catalogue_list": cycle_map, "total_count": sittings.count()}
564+
# Apply term filter to sittings if provided
565+
if term_filter:
566+
sittings_query = sittings_query.filter(cycle__term=term_filter)
567+
568+
total_count = sittings_query.count()
569+
570+
data = {
571+
"catalogue_list": cycle_map,
572+
"total_count": total_count,
573+
}
543574

544575
if not is_dropdown:
545-
for sitting in sittings:
576+
# Use select_related to efficiently fetch related cycle data
577+
for sitting in sittings_query.order_by("date").select_related("cycle"):
546578
term = sitting.cycle.term
547579
session = sitting.cycle.session
548580
meeting = sitting.cycle.meeting
549581

550-
data["catalogue_list"][term][session][meeting]["sitting_list"].append(
551-
SittingSerializer(sitting).data
552-
)
582+
# Use a minimal serializer or manually create dict to avoid serialization overhead
583+
sitting_data = {
584+
"sitting_id": sitting.sitting_id,
585+
"date": sitting.date,
586+
"filename": sitting.filename,
587+
"has_dataset": sitting.has_dataset,
588+
# "is_final": sitting.is_final,
589+
}
590+
591+
cycle_map[term][session][meeting]["sitting_list"].append(sitting_data)
553592

554593
return JsonResponse(data)
555594

0 commit comments

Comments
 (0)