manager: reduce number of queries when listing events (#38699)
This commit is contained in:
parent
61496b5cdf
commit
6988b225c9
|
@ -20,11 +20,12 @@ import math
|
|||
import requests
|
||||
import vobject
|
||||
|
||||
import django
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Q
|
||||
from django.db.models import Count, Q, Case, When
|
||||
from django.urls import reverse
|
||||
from django.utils.dates import WEEKDAYS
|
||||
from django.utils.encoding import force_text
|
||||
|
@ -358,6 +359,41 @@ class Event(models.Model):
|
|||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(qs):
|
||||
if django.VERSION < (2, 0):
|
||||
return qs.annotate(
|
||||
booked_places_count=Count(
|
||||
Case(
|
||||
When(
|
||||
booking__cancellation_datetime__isnull=True,
|
||||
booking__in_waiting_list=False,
|
||||
then='booking',
|
||||
)
|
||||
)
|
||||
),
|
||||
waiting_list_count=Count(
|
||||
Case(
|
||||
When(
|
||||
booking__cancellation_datetime__isnull=True,
|
||||
booking__in_waiting_list=True,
|
||||
then='booking',
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
else:
|
||||
return qs.annotate(
|
||||
booked_places_count=Count(
|
||||
'booking',
|
||||
filter=Q(booking__cancellation_datetime__isnull=True, booking__in_waiting_list=False),
|
||||
),
|
||||
waiting_list_count=Count(
|
||||
'booking',
|
||||
filter=Q(booking__cancellation_datetime__isnull=True, booking__in_waiting_list=True),
|
||||
),
|
||||
)
|
||||
|
||||
@property
|
||||
def booked_places(self):
|
||||
return self.booking_set.filter(cancellation_datetime__isnull=True, in_waiting_list=False).count()
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
{% if object_list %}
|
||||
<ul class="objects-list single-links">
|
||||
{% for event in object_list %}
|
||||
<li class="{% if event.booked_places > event.places %}overbooking{% endif %}
|
||||
<li class="{% if event.booked_places_count > event.places %}overbooking{% endif %}
|
||||
{% if event.full %}full{% endif %}
|
||||
{% if not event.in_bookable_period %}not-{% endif %}bookable"
|
||||
{% if event.places %}
|
||||
data-total="{{event.places}}" data-booked="{{event.booked_places}}"
|
||||
data-total="{{event.places}}" data-booked="{{event.booked_places_count}}"
|
||||
{% elif event.waiting_list_places %}
|
||||
data-total="{{event.waiting_list_places}}" data-booked="{{event.waiting_list}}"
|
||||
data-total="{{event.waiting_list_places}}" data-booked="{{event.waiting_list_count}}"
|
||||
{% endif %}
|
||||
><a href="{% url 'chrono-manager-event-view' pk=agenda.id event_pk=event.id %}">
|
||||
{% if event.label %}{{event.label}} / {% endif %}
|
||||
|
@ -22,11 +22,11 @@
|
|||
{% if event.full %}/ <span class="full">{% trans "full" %}</span>{% endif %}
|
||||
(
|
||||
{% if event.places %}
|
||||
{% blocktrans with places=event.places booked_places=event.booked_places %}{{ places }} places, {{ booked_places }} booked places{% endblocktrans %}
|
||||
{% blocktrans with places=event.places booked_places=event.booked_places_count %}{{ places }} places, {{ booked_places }} booked places{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% if event.places and event.waiting_list_places %} / {% endif %}
|
||||
{% if event.waiting_list_places %}
|
||||
{% blocktrans with places=event.waiting_list_places waiting_places=event.waiting_list %}
|
||||
{% blocktrans with places=event.waiting_list_places waiting_places=event.waiting_list_count %}
|
||||
{{waiting_places}} on {{ places }} in waiting list
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
<div>
|
||||
{% if object.event_set.count %}
|
||||
<ul class="objects-list single-links">
|
||||
{% for event in object.event_set.all %}
|
||||
<li class="{% if event.booked_places > event.places %}overbooking{% endif %}
|
||||
{% for event in view.get_events %}
|
||||
<li class="{% if event.booked_places_count > event.places %}overbooking{% endif %}
|
||||
{% if event.full %}full{% endif %}
|
||||
{% if not event.in_bookable_period %}not-{% endif %}bookable"
|
||||
{% if event.places %}
|
||||
data-total="{{event.places}}" data-booked="{{event.booked_places}}"
|
||||
data-total="{{event.places}}" data-booked="{{event.booked_places_count}}"
|
||||
{% elif event.waiting_list_places %}
|
||||
data-total="{{event.waiting_list_places}}" data-booked="{{event.waiting_list}}"
|
||||
data-total="{{event.waiting_list_places}}" data-booked="{{event.waiting_list_count}}"
|
||||
{% endif %}
|
||||
><a rel="popup" href="{% url 'chrono-manager-event-edit' pk=agenda.id event_pk=event.id %}?next=settings">
|
||||
{% if event.label %}{{event.label}} / {% endif %}
|
||||
|
@ -28,11 +28,11 @@
|
|||
{% if event.full %}/ <span class="full">{% trans "full" %}</span>{% endif %}
|
||||
(
|
||||
{% if event.places %}
|
||||
{% blocktrans with places=event.places booked_places=event.booked_places %}{{ places }} places, {{ booked_places }} booked places{% endblocktrans %}
|
||||
{% blocktrans with places=event.places booked_places=event.booked_places_count %}{{ places }} places, {{ booked_places }} booked places{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% if event.places and event.waiting_list_places %} / {% endif %}
|
||||
{% if event.waiting_list_places %}
|
||||
{% blocktrans with places=event.waiting_list_places waiting_places=event.waiting_list %}
|
||||
{% blocktrans with places=event.waiting_list_places waiting_places=event.waiting_list_count %}
|
||||
{{waiting_places}} on {{ places }} in waiting list
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
|
|
|
@ -420,6 +420,12 @@ agenda_day_view = AgendaDayView.as_view()
|
|||
|
||||
|
||||
class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
||||
def get_queryset(self):
|
||||
qs = super(AgendaMonthView, self).get_queryset()
|
||||
if self.agenda.kind == 'meetings':
|
||||
return qs
|
||||
return Event.annotate_queryset(qs)
|
||||
|
||||
def get_template_names(self):
|
||||
return ['chrono/manager_%s_agenda_month_view.html' % self.agenda.kind]
|
||||
|
||||
|
@ -621,6 +627,9 @@ class ManagedDeskSubobjectMixin(object):
|
|||
class AgendaSettings(ManagedAgendaMixin, DetailView):
|
||||
model = Agenda
|
||||
|
||||
def get_events(self):
|
||||
return Event.annotate_queryset(Event.objects.filter(agenda=self.agenda).select_related('agenda'))
|
||||
|
||||
def get_template_names(self):
|
||||
return ['chrono/manager_%s_agenda_settings.html' % self.agenda.kind]
|
||||
|
||||
|
|
|
@ -455,3 +455,30 @@ def test_management_role_deletion():
|
|||
|
||||
Agenda.objects.get(id=agenda.id).view_role is None
|
||||
Agenda.objects.get(id=agenda.id).edit_role is None
|
||||
|
||||
|
||||
def test_event_bookings_annotation():
|
||||
agenda = Agenda(label='test', kind='events')
|
||||
agenda.save()
|
||||
event = Event(start_datetime=now(), label='foo', places=10, waiting_list_places=10, agenda=agenda)
|
||||
event.save()
|
||||
event2 = Event(start_datetime=now(), label='bar', places=10, waiting_list_places=10, agenda=agenda)
|
||||
event2.save()
|
||||
|
||||
Booking(event=event).save()
|
||||
Booking(event=event).save()
|
||||
Booking(event=event, cancellation_datetime=now()).save()
|
||||
Booking(event=event, in_waiting_list=True).save()
|
||||
Booking(event=event, in_waiting_list=True, cancellation_datetime=now()).save()
|
||||
|
||||
Booking(event=event2).save()
|
||||
Booking(event=event2).save()
|
||||
Booking(event=event2).save()
|
||||
|
||||
for event in Event.annotate_queryset(Event.objects.filter(agenda=agenda)):
|
||||
if event.label == 'foo':
|
||||
assert event.booked_places_count == 2
|
||||
assert event.waiting_list_count == 1
|
||||
elif event.label == 'bar':
|
||||
assert event.booked_places_count == 3
|
||||
assert event.waiting_list_count == 0
|
||||
|
|
Loading…
Reference in New Issue