forked from CGM_Public/pretix_original
Refactor query for check-in count
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Exists, F, Max, OuterRef, Q, Subquery
|
from django.db.models import Count, Exists, F, Max, OuterRef, Q, Subquery
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||||
from django_scopes import ScopedManager
|
from django_scopes import ScopedManager
|
||||||
@@ -91,13 +91,24 @@ class CheckinList(LoggedModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def checkin_count(self):
|
def checkin_count(self):
|
||||||
return self.event.cache.get_or_set(
|
def _get_count():
|
||||||
'checkin_list_{}_checkin_count'.format(self.pk),
|
qs = self.positions.using(settings.DATABASE_REPLICA).annotate(
|
||||||
lambda: self.positions.using(settings.DATABASE_REPLICA).annotate(
|
|
||||||
checkedin=Exists(Checkin.objects.filter(list_id=self.pk, position=OuterRef('pk'), type=Checkin.TYPE_ENTRY,))
|
checkedin=Exists(Checkin.objects.filter(list_id=self.pk, position=OuterRef('pk'), type=Checkin.TYPE_ENTRY,))
|
||||||
).filter(
|
).filter(
|
||||||
checkedin=True
|
checkedin=True
|
||||||
).count(),
|
)
|
||||||
|
# A simple .count() call causes Django's SQL generator to generate a query of the form
|
||||||
|
# ``SELECT COUNT(*) FROM (SELECT foo, bar, EXISTS(…) FROM pretixbase_orderposition …) subquery``, which has been
|
||||||
|
# observed to trick PostgreSQL's query planner into really bad decisions in some cases. We therefore trick Django
|
||||||
|
# into always generating a ``SELECT COUNT(*), 1 FROM pretixbase_orderposition WHERE …`` query.
|
||||||
|
res = list(qs.order_by().annotate(v=models.Value('1', output_field=models.IntegerField())).values('v').annotate(c=Count('*')))
|
||||||
|
if not res:
|
||||||
|
return 0
|
||||||
|
return res[0]['c']
|
||||||
|
|
||||||
|
return self.event.cache.get_or_set(
|
||||||
|
'checkin_list_{}_checkin_count'.format(self.pk),
|
||||||
|
_get_count,
|
||||||
60
|
60
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user