Projet

Général

Profil

0002-manager-reduce-querysets-on-agenda-settings-page-486.patch

Lauréline Guérin, 30 novembre 2020 10:18

Télécharger (8,91 ko)

Voir les différences:

Subject: [PATCH 2/2] manager: reduce querysets on agenda settings page
 (#48624)

 chrono/agendas/models.py | 13 +++++--------
 chrono/manager/views.py  | 18 +++++++++++++++++-
 tests/test_agendas.py    | 17 +++++++++++++++++
 tests/test_manager.py    |  2 +-
 4 files changed, 40 insertions(+), 10 deletions(-)
chrono/agendas/models.py
1210 1210
        return new_desk
1211 1211

  
1212 1212
    def get_exceptions_within_two_weeks(self):
1213
        # FIXME : optimize DB queries, on the settings view this is called once per desk
1213
        # prefetched_exceptions contains desks exceptions + unavailability_calendars exceptions
1214 1214
        # default ordering: start_datetime
1215 1215
        in_two_weeks = make_aware(datetime.datetime.today() + datetime.timedelta(days=14))
1216 1216
        exceptions = []
1217
        queryset = TimePeriodException.objects.filter(Q(desk=self) | Q(unavailability_calendar__desks=self))
1218
        for exception in queryset.all():
1217
        for exception in self.prefetched_exceptions:
1219 1218
            if exception.end_datetime < now():
1220 1219
                # exception ends in the past, skip it
1221 1220
                continue
......
1228 1227
        if exceptions:
1229 1228
            return exceptions
1230 1229
        # if none found within the 2 coming weeks, return the next one
1231
        for exception in queryset.all():
1230
        for exception in self.prefetched_exceptions:
1232 1231
            if exception.start_datetime < now():
1233 1232
                # exception starts in the past, skip it
1234 1233
                continue
......
1238 1237

  
1239 1238
    def are_all_exceptions_displayed(self):
1240 1239
        in_two_weeks = self.get_exceptions_within_two_weeks()
1241
        return TimePeriodException.objects.filter(
1242
            Q(desk=self) | Q(unavailability_calendar__desks=self)
1243
        ).count() == len(in_two_weeks)
1240
        return len(self.prefetched_exceptions) == len(in_two_weeks)
1244 1241

  
1245 1242
    def import_timeperiod_exceptions_from_remote_ics(self, ics_url, source=None):
1246 1243
        try:
......
1621 1618

  
1622 1619
    @property
1623 1620
    def read_only(self):
1624
        return self.source and self.source.settings_slug or self.unavailability_calendar
1621
        return self.source and self.source.settings_slug or self.unavailability_calendar_id
1625 1622

  
1626 1623
    class Meta:
1627 1624
        ordering = ['start_datetime']
chrono/manager/views.py
1346 1346
class AgendaSettings(ManagedAgendaMixin, DetailView):
1347 1347
    model = Agenda
1348 1348

  
1349
    def set_agenda(self, **kwargs):
1350
        self.agenda = get_object_or_404(
1351
            Agenda.objects.select_related('edit_role', 'view_role'), pk=kwargs.get('pk')
1352
        )
1353

  
1349 1354
    def get_object(self, *args, **kwargs):
1350 1355
        if self.agenda.kind == 'meetings':
1351 1356
            self.agenda.prefetched_desks = self.agenda.desk_set.all().prefetch_related(
1352
                'timeperiod_set', 'timeperiodexception_set',
1357
                'timeperiod_set', 'unavailability_calendars',
1353 1358
            )
1359
            all_desks_exceptions = TimePeriodException.objects.filter(
1360
                Q(desk__in=self.agenda.prefetched_desks)
1361
                | Q(unavailability_calendar__desks__in=self.agenda.prefetched_desks)
1362
            ).select_related('source')
1363
            for desk in self.agenda.prefetched_desks:
1364
                uc_ids = [uc.pk for uc in desk.unavailability_calendars.all()]
1365
                desk.prefetched_exceptions = [
1366
                    e
1367
                    for e in all_desks_exceptions
1368
                    if e.desk_id == desk.pk or e.unavailability_calendar_id in uc_ids
1369
                ]
1354 1370
        return self.agenda
1355 1371

  
1356 1372
    def get_context_data(self, **kwargs):
tests/test_agendas.py
6 6
import smtplib
7 7

  
8 8

  
9
from django.db.models import Q
9 10
from django.contrib.auth.models import Group, User
10 11
from django.core.files.base import ContentFile
11 12
from django.core.management import call_command
......
862 863

  
863 864

  
864 865
def test_desk_exceptions_within_two_weeks():
866
    def set_prefetched_exceptions(desk):
867
        desk.prefetched_exceptions = TimePeriodException.objects.filter(
868
            Q(desk=desk) | Q(unavailability_calendar__desks=desk)
869
        )
870

  
865 871
    agenda = Agenda.objects.create(label='Agenda', kind='meetings')
866 872
    desk = Desk.objects.create(agenda=agenda, label='Desk')
867 873

  
868 874
    # no exception
875
    set_prefetched_exceptions(desk)
869 876
    assert list(desk.get_exceptions_within_two_weeks()) == []
870 877

  
871 878
    # exception ends in the past
......
874 881
        start_datetime=now() - datetime.timedelta(days=2),
875 882
        end_datetime=now() - datetime.timedelta(days=1),
876 883
    )
884
    set_prefetched_exceptions(desk)
877 885
    assert list(desk.get_exceptions_within_two_weeks()) == []
878 886

  
879 887
    # exception ends in the future - 14 days
......
881 889
    # but starts in the past
882 890
    exception.start_datetime = now() - datetime.timedelta(days=2)
883 891
    exception.save()
892
    set_prefetched_exceptions(desk)
884 893
    assert list(desk.get_exceptions_within_two_weeks()) == [exception]
885 894

  
886 895
    # exception ends in the future - 14 days
......
888 897
    # but starts in the future
889 898
    exception.start_datetime = now() + datetime.timedelta(days=2)
890 899
    exception.save()
900
    set_prefetched_exceptions(desk)
891 901
    assert list(desk.get_exceptions_within_two_weeks()) == [exception]
892 902

  
893 903
    # exception ends in the future + 14 days
......
895 905
    # but starts in the past
896 906
    exception.start_datetime = now() - datetime.timedelta(days=2)
897 907
    exception.save()
908
    set_prefetched_exceptions(desk)
898 909
    assert list(desk.get_exceptions_within_two_weeks()) == [exception]
899 910

  
900 911
    # create another one, very far way from now
......
909 920
    # but starts in the future - 14 days
910 921
    exception.start_datetime = now() + datetime.timedelta(days=2)
911 922
    exception.save()
923
    set_prefetched_exceptions(desk)
912 924
    assert list(desk.get_exceptions_within_two_weeks()) == [exception]
913 925

  
914 926
    # exception ends in the future + 14 days
......
916 928
    # but starts in the future + 14 days
917 929
    exception.start_datetime = now() + datetime.timedelta(days=21)
918 930
    exception.save()
931
    set_prefetched_exceptions(desk)
919 932
    assert list(desk.get_exceptions_within_two_weeks()) == [exception]
920 933

  
921 934
    # exception in the past
922 935
    exception.end_datetime = now() - datetime.timedelta(days=20)
923 936
    exception.start_datetime = now() - datetime.timedelta(days=21)
924 937
    exception.save()
938
    set_prefetched_exceptions(desk)
925 939
    assert list(desk.get_exceptions_within_two_weeks()) == [exception2]
926 940

  
927 941
    # check ordering of the queryset: exception is after exception2
......
931 945
    exception2.start_datetime = now() + datetime.timedelta(days=5)
932 946
    exception2.end_datetime = now() + datetime.timedelta(days=6)
933 947
    exception2.save()
948
    set_prefetched_exceptions(desk)
934 949
    assert list(desk.get_exceptions_within_two_weeks()) == [exception2, exception]
935 950

  
936 951
    # add an exception from unavailability calendar
......
941 956
        end_datetime=now() + datetime.timedelta(days=3),
942 957
    )
943 958
    unavailability_calendar.desks.add(desk)
959
    set_prefetched_exceptions(desk)
944 960
    assert list(desk.get_exceptions_within_two_weeks()) == [exception3, exception2, exception]
945 961

  
946 962
    # change it
947 963
    exception3.start_datetime = now() + datetime.timedelta(days=7)
948 964
    exception3.end_datetime = now() + datetime.timedelta(days=8)
949 965
    exception3.save()
966
    set_prefetched_exceptions(desk)
950 967
    assert list(desk.get_exceptions_within_two_weeks()) == [exception2, exception3, exception]
951 968

  
952 969

  
tests/test_manager.py
1042 1042
    app = login(app)
1043 1043
    with CaptureQueriesContext(connection) as ctx:
1044 1044
        app.get('/manage/agendas/%s/settings' % agenda.pk)
1045
        assert len(ctx.captured_queries) == 63
1045
        assert len(ctx.captured_queries) == 12
1046 1046

  
1047 1047

  
1048 1048
def test_agenda_resources(app, admin_user):
1049
-