Further SQL optimizations

This commit is contained in:
Raphael Michel
2016-11-08 16:58:48 +01:00
parent 4c80ec17bf
commit 37598ed914
8 changed files with 65 additions and 23 deletions

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.2 on 2016-11-08 15:42
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0044_auto_20161101_1610'),
]
operations = [
migrations.AlterField(
model_name='cartposition',
name='expires',
field=models.DateTimeField(db_index=True, verbose_name='Expiration date'),
),
migrations.AlterField(
model_name='voucher',
name='redeemed',
field=models.BooleanField(db_index=True, default=False, verbose_name='Redeemed'),
),
migrations.AlterField(
model_name='voucher',
name='valid_until',
field=models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Valid until'),
),
]

View File

@@ -582,7 +582,7 @@ class Quota(LoggedModel):
Q(redeemed=False) &
Q(Q(valid_until__isnull=True) | Q(valid_until__gte=now_dt)) &
Q(Q(self._position_lookup) | Q(quota=self))
).distinct().count()
).values('id').distinct().count()
def count_in_cart(self, now_dt: datetime=None) -> int:
from pretix.base.models import CartPosition
@@ -595,21 +595,22 @@ class Quota(LoggedModel):
& Q(Q(voucher__valid_until__isnull=True) | Q(voucher__valid_until__gte=now_dt))
) &
self._position_lookup
).distinct().count()
).values('id').distinct().count()
def count_pending_orders(self) -> dict:
from pretix.base.models import Order, OrderPosition
# This query has beeen benchmarked against a Count('id', distinct=True) aggregate and won by a small margin.
return OrderPosition.objects.filter(
self._position_lookup, order__status=Order.STATUS_PENDING,
).distinct().count()
).values('id').distinct().count()
def count_paid_orders(self):
from pretix.base.models import Order, OrderPosition
return OrderPosition.objects.filter(
self._position_lookup, order__status=Order.STATUS_PAID
).distinct().count()
).values('id').distinct().count()
@cached_property
def _position_lookup(self) -> Q:

View File

@@ -515,7 +515,8 @@ class CartPosition(AbstractPosition):
auto_now_add=True
)
expires = models.DateTimeField(
verbose_name=_("Expiration date")
verbose_name=_("Expiration date"),
db_index=True
)
class Meta:

View File

@@ -70,10 +70,11 @@ class Voucher(LoggedModel):
)
redeemed = models.BooleanField(
verbose_name=_("Redeemed"),
default=False
default=False,
db_index=True
)
valid_until = models.DateTimeField(
blank=True, null=True,
blank=True, null=True, db_index=True,
verbose_name=_("Valid until")
)
block_quota = models.BooleanField(

View File

@@ -4,7 +4,6 @@ from typing import Any, Dict
from django import forms
from django.contrib import messages
from django.db.models import Sum
from django.dispatch import receiver
from django.forms import Form
from django.http import HttpRequest
@@ -13,9 +12,10 @@ from django.utils.translation import ugettext_lazy as _
from pretix.base.decimal import round_decimal
from pretix.base.i18n import I18nFormField, I18nTextarea, LazyI18nString
from pretix.base.models import CartPosition, Event, Order, Quota
from pretix.base.models import Event, Order, Quota
from pretix.base.settings import SettingsSandbox
from pretix.base.signals import register_payment_providers
from pretix.presale.views import get_cart_total
class BasePaymentProvider:
@@ -503,9 +503,7 @@ class FreeOrderProvider(BasePaymentProvider):
messages.success(request, _('The order has been marked as refunded.'))
def is_allowed(self, request: HttpRequest) -> bool:
return CartPosition.objects.filter(
cart_id=request.session.session_key, event=request.event
).aggregate(sum=Sum('price'))['sum'] == 0
return get_cart_total(request) == 0
def order_change_allowed(self, order: Order) -> bool:
return False

View File

@@ -2,7 +2,6 @@ from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator
from django.db.models import Q, Sum
from django.http import HttpResponseNotAllowed
from django.shortcuts import redirect
from django.utils import translation
@@ -10,7 +9,7 @@ from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateResponseMixin
from pretix.base.models import CartPosition, Order
from pretix.base.models import Order
from pretix.base.models.orders import InvoiceAddress
from pretix.base.services.mail import SendMailException
from pretix.base.services.orders import OrderError, perform_order
@@ -18,7 +17,7 @@ from pretix.base.signals import register_payment_providers
from pretix.multidomain.urlreverse import eventreverse
from pretix.presale.forms.checkout import ContactForm, InvoiceAddressForm
from pretix.presale.signals import checkout_flow_steps
from pretix.presale.views import CartMixin
from pretix.presale.views import CartMixin, get_cart_total
from pretix.presale.views.async import AsyncAction
from pretix.presale.views.questions import QuestionsViewMixin
@@ -143,11 +142,12 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
@cached_property
def invoice_address(self):
iapk = self.request.session.get('invoice_address')
if not iapk:
return InvoiceAddress()
try:
return InvoiceAddress.objects.get(
pk=self.request.session.get('invoice_address'),
order__isnull=True
)
return InvoiceAddress.objects.get(pk=iapk, order__isnull=True)
except InvoiceAddress.DoesNotExist:
return InvoiceAddress()
@@ -218,9 +218,7 @@ class PaymentStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
@cached_property
def _total_order_value(self):
return CartPosition.objects.filter(
Q(cart_id=self.request.session.session_key) & Q(event=self.request.event)
).aggregate(sum=Sum('price'))['sum']
return get_cart_total(self.request)
@cached_property
def provider_forms(self):

View File

@@ -2,6 +2,7 @@ from datetime import timedelta
from decimal import Decimal
from itertools import groupby
from django.db.models import Sum
from django.utils.functional import cached_property
from django.utils.timezone import now
@@ -106,6 +107,17 @@ def get_cart(request):
return request._cart_cache
def get_cart_total(request):
if not hasattr(request, '_cart_total_cache'):
if hasattr(request, '_cart_cache'):
request._cart_total_cache = sum(i.price for i in request._cart_cache)
else:
request._cart_total_cache = CartPosition.objects.filter(
cart_id=request.session.session_key, event=request.event
).aggregate(sum=Sum('price'))['sum']
return request._cart_total_cache
class EventViewMixin:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

View File

@@ -3,6 +3,7 @@ from django.utils.functional import cached_property
from pretix.base.models import CartPosition, OrderPosition, QuestionAnswer
from pretix.presale.forms.checkout import QuestionsForm
from pretix.presale.views import get_cart
class QuestionsViewMixin:
@@ -14,7 +15,7 @@ class QuestionsViewMixin:
submitted at once.
"""
formlist = []
for cr in self.positions:
for cr in get_cart(self.request):
cartpos = cr if isinstance(cr, CartPosition) else None
orderpos = cr if isinstance(cr, OrderPosition) else None
form = QuestionsForm(event=self.request.event,