0002-manager-reduce-querysets-on-agenda-settings-page-486.patch
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 |
- |