From b8415b63ddc907b67aef3e3b7b8d67ae20934ff6 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Thu, 21 Oct 2021 17:01:44 +0200 Subject: [PATCH 5/5] api: add prefetching to recurring events endpoints (#57957) --- chrono/agendas/models.py | 10 +++++----- chrono/api/views.py | 18 ++++++++++++------ tests/api/test_datetimes.py | 2 +- tests/api/test_fillslot.py | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py index eb3ea4c1..eb738948 100644 --- a/chrono/agendas/models.py +++ b/chrono/agendas/models.py @@ -744,11 +744,11 @@ class Agenda(models.Model): return entries def get_open_recurring_events(self): - return self.event_set.filter( - Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now()), - recurrence_days__isnull=False, - recurrence_end_date__gt=localtime(now()).date(), - ) + return [ + e + for e in self.prefetched_recurring_events + if e.recurrence_end_date and e.recurrence_end_date > localtime(now()).date() + ] def add_event_recurrences( self, diff --git a/chrono/api/views.py b/chrono/api/views.py index 7e9f58ee..e2904a65 100644 --- a/chrono/api/views.py +++ b/chrono/api/views.py @@ -1068,6 +1068,7 @@ class RecurringEventsList(APIView): agenda_slugs = get_agendas_from_request(request) agendas = get_objects_from_slugs(agenda_slugs, qs=Agenda.objects.filter(kind='events')) + agendas = Agenda.prefetch_recurring_events(agendas) events = [] for agenda in agendas: @@ -1596,7 +1597,7 @@ class RecurringFillslots(APIView): agenda_slugs = get_agendas_from_request(request) agendas = get_objects_from_slugs(agenda_slugs, qs=Agenda.objects.filter(kind='events')) - context = {'allowed_agenda_slugs': agenda_slugs, 'agendas': agendas} + context = {'allowed_agenda_slugs': agenda_slugs, 'agendas': Agenda.prefetch_recurring_events(agendas)} serializer = self.serializer_class(data=request.data, partial=True, context=context) if not serializer.is_valid(): raise APIError( @@ -1607,6 +1608,7 @@ class RecurringFillslots(APIView): ) payload = serializer.validated_data user_external_id = payload['user_external_id'] + agendas = Agenda.prefetch_events_and_exceptions(agendas, user_external_id=user_external_id) event_filter = Q() for agenda_slug, days_by_event in payload['slots'].items(): @@ -1622,11 +1624,15 @@ class RecurringFillslots(APIView): if end_datetime: events_to_book = events_to_book.filter(start_datetime__lte=end_datetime) - events_to_unbook = list( - agenda.event_set.filter(booking__user_external_id=user_external_id, primary_event__isnull=False) - .exclude(pk__in=events_to_book) - .values_list('pk', flat=True) - ) + events_to_book_ids = set(events_to_book.values_list('pk', flat=True)) + events_to_unbook = [ + e.pk + for agenda in agendas + for e in agenda.prefetched_events + if (e.user_places_count or e.user_waiting_places_count) + and e.primary_event_id + and e.pk not in events_to_book_ids + ] events_to_book = events_to_book.exclude(booking__user_external_id=user_external_id) full_events = list(events_to_book.filter(full=True)) diff --git a/tests/api/test_datetimes.py b/tests/api/test_datetimes.py index c06279d1..ee2ebb02 100644 --- a/tests/api/test_datetimes.py +++ b/tests/api/test_datetimes.py @@ -1428,7 +1428,7 @@ def test_recurring_events_api_list_multiple_agendas_queries(app): with CaptureQueriesContext(connection) as ctx: resp = app.get('/api/agendas/recurring-events/?agendas=%s' % ','.join(str(i) for i in range(20))) assert len(resp.json['data']) == 40 - assert len(ctx.captured_queries) == 23 + assert len(ctx.captured_queries) == 3 @pytest.mark.freeze_time('2021-05-06 14:00') diff --git a/tests/api/test_fillslot.py b/tests/api/test_fillslot.py index 9c43cb34..0d8889f2 100644 --- a/tests/api/test_fillslot.py +++ b/tests/api/test_fillslot.py @@ -2405,7 +2405,7 @@ def test_recurring_events_api_fillslots_multiple_agendas_queries(app, user): params={'slots': events_to_book, 'user_external_id': 'user'}, ) assert resp.json['booking_count'] == 180 - assert len(ctx.captured_queries) == 36 + assert len(ctx.captured_queries) == 16 @pytest.mark.freeze_time('2021-09-06 12:00') -- 2.30.2