api: reduce number of sql queries in datetimes API (#42142)
This commit is contained in:
parent
124ff4b0aa
commit
9d0b76c82a
|
@ -434,9 +434,9 @@ class TimePeriod(models.Model):
|
|||
|
||||
return effective_timeperiods
|
||||
|
||||
def get_time_slots(self, min_datetime, max_datetime, meeting_type):
|
||||
def get_time_slots(self, min_datetime, max_datetime, meeting_type, base_duration):
|
||||
meeting_duration = datetime.timedelta(minutes=meeting_type.duration)
|
||||
duration = datetime.timedelta(minutes=self.desk.agenda.get_base_meeting_duration())
|
||||
duration = datetime.timedelta(minutes=base_duration)
|
||||
|
||||
real_min_datetime = min_datetime + datetime.timedelta(days=self.weekday - min_datetime.weekday())
|
||||
if real_min_datetime < min_datetime:
|
||||
|
|
|
@ -79,20 +79,26 @@ def get_all_slots(agenda, meeting_type):
|
|||
base_agenda = agenda
|
||||
|
||||
open_slots = {}
|
||||
time_periods_by_agenda = {}
|
||||
for agenda in agendas:
|
||||
open_slots[agenda] = defaultdict(lambda: Intervals())
|
||||
open_slots[agenda.id] = defaultdict(lambda: Intervals())
|
||||
time_periods_by_agenda[agenda.id] = []
|
||||
|
||||
# preload time periods
|
||||
for period in TimePeriod.objects.filter(desk__agenda__in=agendas).prefetch_related('desk__agenda'):
|
||||
time_periods_by_agenda[period.desk.agenda_id].append(period)
|
||||
|
||||
base_agenda_excluded_timeperiods = base_agenda.excluded_timeperiods.all()
|
||||
for agenda in agendas:
|
||||
base_duration = agenda.get_base_meeting_duration()
|
||||
used_time_period_filters = time_period_filters.copy()
|
||||
if used_time_period_filters['min_datetime'] is None:
|
||||
used_time_period_filters['min_datetime'] = get_min_datetime(agenda)
|
||||
if used_time_period_filters['max_datetime'] is None:
|
||||
used_time_period_filters['max_datetime'] = get_max_datetime(agenda)
|
||||
|
||||
for raw_time_period in TimePeriod.objects.filter(desk__agenda=agenda):
|
||||
for time_period in raw_time_period.get_effective_timeperiods(
|
||||
base_agenda.excluded_timeperiods.all()
|
||||
):
|
||||
for raw_time_period in time_periods_by_agenda[agenda.id]:
|
||||
for time_period in raw_time_period.get_effective_timeperiods(base_agenda_excluded_timeperiods):
|
||||
duration = (
|
||||
datetime.datetime.combine(base_date, time_period.end_time)
|
||||
- datetime.datetime.combine(base_date, time_period.start_time)
|
||||
|
@ -100,18 +106,22 @@ def get_all_slots(agenda, meeting_type):
|
|||
if duration < meeting_type.duration:
|
||||
# skip time period that can't even hold a single meeting
|
||||
continue
|
||||
for slot in time_period.get_time_slots(**used_time_period_filters):
|
||||
for slot in time_period.get_time_slots(
|
||||
base_duration=base_duration, **used_time_period_filters
|
||||
):
|
||||
slot.full = False
|
||||
open_slots[agenda][time_period.desk_id].add(slot.start_datetime, slot.end_datetime, slot)
|
||||
open_slots[agenda.id][time_period.desk_id].add(
|
||||
slot.start_datetime, slot.end_datetime, slot
|
||||
)
|
||||
|
||||
# remove excluded slot
|
||||
for agenda in agendas:
|
||||
excluded_slot_by_desk = get_exceptions_by_desk(agenda)
|
||||
|
||||
for desk, excluded_interval in excluded_slot_by_desk.items():
|
||||
for desk_id, excluded_interval in excluded_slot_by_desk.items():
|
||||
for interval in excluded_interval:
|
||||
begin, end = interval
|
||||
open_slots[agenda][desk].remove_overlap(localtime(begin), localtime(end))
|
||||
open_slots[agenda.id][desk_id].remove_overlap(localtime(begin), localtime(end))
|
||||
|
||||
for agenda in agendas:
|
||||
used_min_datetime = min_datetime
|
||||
|
@ -130,15 +140,15 @@ def get_all_slots(agenda, meeting_type):
|
|||
.select_related('meeting_type')
|
||||
.exclude(booking__cancellation_datetime__isnull=False)
|
||||
):
|
||||
for slot in open_slots[agenda][event.desk_id].search_data(
|
||||
for slot in open_slots[agenda.id][event.desk_id].search_data(
|
||||
event.start_datetime, event.end_datetime
|
||||
):
|
||||
slot.full = True
|
||||
|
||||
slots = []
|
||||
for agenda in agendas:
|
||||
for desk in open_slots[agenda]:
|
||||
slots.extend(open_slots[agenda][desk].iter_data())
|
||||
for desk_id in open_slots[agenda.id]:
|
||||
slots.extend(open_slots[agenda.id][desk_id].iter_data())
|
||||
slots.sort(key=lambda slot: slot.start_datetime)
|
||||
return slots
|
||||
|
||||
|
|
|
@ -2913,8 +2913,10 @@ def test_virtual_agendas_meetings_datetimes_multiple_agendas(app, time_zone, moc
|
|||
bar_desk_1 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 1')
|
||||
create_time_perdiods(bar_desk_1, end=13) # bar_agenda has two more slots each day
|
||||
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda)
|
||||
resp = app.get(api_url)
|
||||
assert len(resp.json['data']) == 12
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get(api_url)
|
||||
assert len(resp.json['data']) == 12
|
||||
assert len(ctx.captured_queries) == 16
|
||||
|
||||
# simulate booking
|
||||
dt = datetime.datetime.strptime(resp.json['data'][2]['id'].split(':')[1], '%Y-%m-%d-%H%M')
|
||||
|
|
|
@ -25,6 +25,7 @@ def test_timeperiod_time_slots():
|
|||
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
||||
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
||||
meeting_type=meeting_type,
|
||||
base_duration=agenda.get_base_meeting_duration(),
|
||||
)
|
||||
events = list(sorted(events, key=lambda x: x.start_datetime))
|
||||
assert events[0].start_datetime.timetuple()[:5] == (2016, 9, 5, 9, 0)
|
||||
|
@ -43,6 +44,7 @@ def test_timeperiod_time_slots():
|
|||
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
||||
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
||||
meeting_type=meeting_type,
|
||||
base_duration=agenda.get_base_meeting_duration(),
|
||||
)
|
||||
events = list(sorted(events, key=lambda x: x.start_datetime))
|
||||
assert events[0].start_datetime.timetuple()[:5] == (2016, 9, 6, 9, 0)
|
||||
|
@ -57,6 +59,7 @@ def test_timeperiod_time_slots():
|
|||
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
||||
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
||||
meeting_type=meeting_type,
|
||||
base_duration=agenda.get_base_meeting_duration(),
|
||||
)
|
||||
events = list(sorted(events, key=lambda x: x.start_datetime))
|
||||
assert events[0].start_datetime.timetuple()[:5] == (2016, 9, 1, 9, 0)
|
||||
|
@ -71,6 +74,7 @@ def test_timeperiod_time_slots():
|
|||
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
||||
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
||||
meeting_type=meeting_type,
|
||||
base_duration=agenda.get_base_meeting_duration(),
|
||||
)
|
||||
events = list(sorted(events, key=lambda x: x.start_datetime))
|
||||
assert events[0].start_datetime.timetuple()[:5] == (2016, 9, 2, 9, 0)
|
||||
|
@ -85,6 +89,7 @@ def test_timeperiod_time_slots():
|
|||
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
||||
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
||||
meeting_type=meeting_type,
|
||||
base_duration=agenda.get_base_meeting_duration(),
|
||||
)
|
||||
events = list(sorted(events, key=lambda x: x.start_datetime))
|
||||
assert events[0].start_datetime.timetuple()[:5] == (2016, 9, 3, 9, 0)
|
||||
|
@ -101,6 +106,7 @@ def test_timeperiod_time_slots():
|
|||
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
||||
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
||||
meeting_type=meeting_type,
|
||||
base_duration=agenda.get_base_meeting_duration(),
|
||||
)
|
||||
events = list(sorted(events, key=lambda x: x.start_datetime))
|
||||
assert events[0].start_datetime.timetuple()[:5] == (2016, 9, 3, 9, 0)
|
||||
|
@ -230,6 +236,7 @@ def test_timeperiod_midnight_overlap_time_slots():
|
|||
min_datetime=make_aware(datetime.datetime(2016, 9, 1)),
|
||||
max_datetime=make_aware(datetime.datetime(2016, 10, 1)),
|
||||
meeting_type=meeting_type,
|
||||
base_duration=agenda.get_base_meeting_duration(),
|
||||
)
|
||||
events = list(sorted(events, key=lambda x: x.start_datetime))
|
||||
assert events[0].start_datetime.timetuple()[:5] == (2016, 9, 5, 21, 0)
|
||||
|
|
Loading…
Reference in New Issue