forked from CGM_Public/pretix_original
Merge pull request #1874 from pretix/perf2020
This commit is contained in:
@@ -902,7 +902,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def positions_with_tickets(self):
|
def positions_with_tickets(self):
|
||||||
for op in self.positions.all():
|
for op in self.positions.select_related('item'):
|
||||||
if not op.generate_ticket:
|
if not op.generate_ticket:
|
||||||
continue
|
continue
|
||||||
yield op
|
yield op
|
||||||
@@ -1155,7 +1155,7 @@ class AbstractPosition(models.Model):
|
|||||||
(2) questions: a list of Question objects, extended by an 'answer' property
|
(2) questions: a list of Question objects, extended by an 'answer' property
|
||||||
"""
|
"""
|
||||||
self.answ = {}
|
self.answ = {}
|
||||||
for a in self.answers.all():
|
for a in getattr(self, 'answerlist', self.answers.all()): # use prefetch_related cache from get_cart
|
||||||
self.answ[a.question_id] = a
|
self.answ[a.question_id] = a
|
||||||
|
|
||||||
# We need to clone our question objects, otherwise we will override the cached
|
# We need to clone our question objects, otherwise we will override the cached
|
||||||
|
|||||||
@@ -113,10 +113,11 @@ class QuotaAvailability:
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
def _write_cache(self, quotas, now_dt):
|
def _write_cache(self, quotas, now_dt):
|
||||||
events = {q.event for q in quotas}
|
# We used to also delete item_quota_cache:* from the event cache here, but as the cache
|
||||||
|
# gets more complex, this does not seem worth it. The cache is only present for up to
|
||||||
|
# 5 seconds to prevent high peaks, and a 5-second delay in availability is usually
|
||||||
|
# tolerable
|
||||||
update = []
|
update = []
|
||||||
for e in events:
|
|
||||||
e.cache.delete('item_quota_cache')
|
|
||||||
for q in quotas:
|
for q in quotas:
|
||||||
rewrite_cache = self._count_waitinglist and (
|
rewrite_cache = self._count_waitinglist and (
|
||||||
not q.cache_is_hot(now_dt) or self.results[q][0] > q.cached_availability_state
|
not q.cache_is_hot(now_dt) or self.results[q][0] > q.cached_availability_state
|
||||||
|
|||||||
@@ -673,7 +673,7 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
|
|||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
class PaymentStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
|
class PaymentStep(CartMixin, TemplateFlowStep):
|
||||||
priority = 200
|
priority = 200
|
||||||
identifier = "payment"
|
identifier = "payment"
|
||||||
template_name = "pretixpresale/event/checkout_payment.html"
|
template_name = "pretixpresale/event/checkout_payment.html"
|
||||||
|
|||||||
@@ -313,7 +313,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
{% if order.user_change_allowed or order.user_cancel_allowed %}
|
{% if user_change_allowed or user_cancel_allowed %}
|
||||||
<div class="panel panel-primary panel-cancellation">
|
<div class="panel panel-primary panel-cancellation">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">
|
<h3 class="panel-title">
|
||||||
@@ -321,7 +321,7 @@
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{% if order.user_change_allowed %}
|
{% if user_change_allowed %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans trimmed %}
|
{% blocktrans trimmed %}
|
||||||
@@ -335,7 +335,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if order.user_cancel_allowed %}
|
{% if user_cancel_allowed %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
{% if order.status == "p" and order.total != 0 %}
|
{% if order.status == "p" and order.total != 0 %}
|
||||||
{% if order.user_cancel_fee >= order.total %}
|
{% if order.user_cancel_fee >= order.total %}
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ from functools import wraps
|
|||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Prefetch, Sum
|
from django.db.models import Exists, OuterRef, Prefetch, Sum
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
from pretix.base.i18n import language
|
from pretix.base.i18n import language
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CartPosition, InvoiceAddress, OrderPosition, QuestionAnswer,
|
CartPosition, InvoiceAddress, ItemAddOn, OrderPosition, Question,
|
||||||
|
QuestionAnswer, QuestionOption,
|
||||||
)
|
)
|
||||||
from pretix.base.services.cart import get_fees
|
from pretix.base.services.cart import get_fees
|
||||||
from pretix.helpers.cookies import set_cookie_without_samesite
|
from pretix.helpers.cookies import set_cookie_without_samesite
|
||||||
@@ -68,12 +69,15 @@ class CartMixin:
|
|||||||
prefetch.append(Prefetch('answers', queryset=QuestionAnswer.objects.prefetch_related('options')))
|
prefetch.append(Prefetch('answers', queryset=QuestionAnswer.objects.prefetch_related('options')))
|
||||||
|
|
||||||
cartpos = queryset.order_by(
|
cartpos = queryset.order_by(
|
||||||
'item__category__position', 'item__category_id', 'item__position', 'item__name', 'variation__value'
|
'item__category__position', 'item__category_id', 'item__position', 'item__name',
|
||||||
|
'variation__value'
|
||||||
).select_related(
|
).select_related(
|
||||||
'item', 'variation', 'addon_to', 'subevent', 'subevent__event', 'subevent__event__organizer', 'seat'
|
'item', 'variation', 'addon_to', 'subevent', 'subevent__event',
|
||||||
|
'subevent__event__organizer', 'seat'
|
||||||
).prefetch_related(
|
).prefetch_related(
|
||||||
*prefetch
|
*prefetch
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
cartpos = self.positions
|
cartpos = self.positions
|
||||||
|
|
||||||
@@ -123,7 +127,7 @@ class CartMixin:
|
|||||||
or pos.pk in has_addons \
|
or pos.pk in has_addons \
|
||||||
or pos.addon_to_id \
|
or pos.addon_to_id \
|
||||||
or pos.item.issue_giftcard \
|
or pos.item.issue_giftcard \
|
||||||
or (answers and (has_attendee_data or pos.item.questions.exists())):
|
or (answers and (has_attendee_data or bool(pos.item.questions.all()))): # do not use .exists() to re-use prefetch cache
|
||||||
return (
|
return (
|
||||||
# standalone positions are grouped by main product position id, addons below them also sorted by position id
|
# standalone positions are grouped by main product position id, addons below them also sorted by position id
|
||||||
i, addon_penalty, pos.pk,
|
i, addon_penalty, pos.pk,
|
||||||
@@ -147,7 +151,8 @@ class CartMixin:
|
|||||||
group.total = group.count * group.price
|
group.total = group.count * group.price
|
||||||
group.net_total = group.count * group.net_price
|
group.net_total = group.count * group.net_price
|
||||||
group.has_questions = answers and k[0] != ""
|
group.has_questions = answers and k[0] != ""
|
||||||
group.tax_rule = group.item.tax_rule
|
if not hasattr(group, 'tax_rule'):
|
||||||
|
group.tax_rule = group.item.tax_rule
|
||||||
|
|
||||||
group.bundle_sum = group.price + sum(a.price for a in has_addons[group.pk])
|
group.bundle_sum = group.price + sum(a.price for a in has_addons[group.pk])
|
||||||
group.bundle_sum_net = group.net_price + sum(a.net_price for a in has_addons[group.pk])
|
group.bundle_sum_net = group.net_price + sum(a.net_price for a in has_addons[group.pk])
|
||||||
@@ -214,6 +219,8 @@ def cart_exists(request):
|
|||||||
|
|
||||||
def get_cart(request):
|
def get_cart(request):
|
||||||
from pretix.presale.views.cart import get_or_create_cart_id
|
from pretix.presale.views.cart import get_or_create_cart_id
|
||||||
|
qqs = request.event.questions.all()
|
||||||
|
qqs = qqs.filter(ask_during_checkin=False, hidden=False)
|
||||||
|
|
||||||
if not hasattr(request, '_cart_cache'):
|
if not hasattr(request, '_cart_cache'):
|
||||||
cart_id = get_or_create_cart_id(request, create=False)
|
cart_id = get_or_create_cart_id(request, create=False)
|
||||||
@@ -222,11 +229,36 @@ def get_cart(request):
|
|||||||
else:
|
else:
|
||||||
request._cart_cache = CartPosition.objects.filter(
|
request._cart_cache = CartPosition.objects.filter(
|
||||||
cart_id=cart_id, event=request.event
|
cart_id=cart_id, event=request.event
|
||||||
|
).annotate(
|
||||||
|
has_addon_choices=Exists(
|
||||||
|
ItemAddOn.objects.filter(
|
||||||
|
base_item_id=OuterRef('item_id')
|
||||||
|
)
|
||||||
|
)
|
||||||
).order_by(
|
).order_by(
|
||||||
'item', 'variation'
|
'item__category__position', 'item__category_id', 'item__position', 'item__name', 'variation__value'
|
||||||
).select_related(
|
).select_related(
|
||||||
'item', 'variation', 'subevent', 'subevent__event', 'subevent__event__organizer',
|
'item', 'variation', 'subevent', 'subevent__event', 'subevent__event__organizer',
|
||||||
'item__tax_rule', 'addon_to'
|
'item__tax_rule', 'addon_to'
|
||||||
|
).select_related(
|
||||||
|
'addon_to'
|
||||||
|
).prefetch_related(
|
||||||
|
'addons', 'addons__item', 'addons__variation',
|
||||||
|
Prefetch('answers',
|
||||||
|
QuestionAnswer.objects.prefetch_related('options'),
|
||||||
|
to_attr='answerlist'),
|
||||||
|
Prefetch('item__questions',
|
||||||
|
qqs.prefetch_related(
|
||||||
|
Prefetch('options', QuestionOption.objects.prefetch_related(Prefetch(
|
||||||
|
# This prefetch statement is utter bullshit, but it actually prevents Django from doing
|
||||||
|
# a lot of queries since ModelChoiceIterator stops trying to be clever once we have
|
||||||
|
# a prefetch lookup on this query...
|
||||||
|
'question',
|
||||||
|
Question.objects.none(),
|
||||||
|
to_attr='dummy'
|
||||||
|
)))
|
||||||
|
).select_related('dependency_question'),
|
||||||
|
to_attr='questions_to_ask')
|
||||||
)
|
)
|
||||||
for cp in request._cart_cache:
|
for cp in request._cart_cache:
|
||||||
cp.event = request.event # Populate field with known value to save queries
|
cp.event = request.event # Populate field with known value to save queries
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ def item_group_by_category(items):
|
|||||||
|
|
||||||
def get_grouped_items(event, subevent=None, voucher=None, channel='web', require_seat=0, base_qs=None, allow_addons=False,
|
def get_grouped_items(event, subevent=None, voucher=None, channel='web', require_seat=0, base_qs=None, allow_addons=False,
|
||||||
quota_cache=None, filter_items=None, filter_categories=None):
|
quota_cache=None, filter_items=None, filter_categories=None):
|
||||||
|
base_qs_set = base_qs is not None
|
||||||
base_qs = base_qs if base_qs is not None else event.items
|
base_qs = base_qs if base_qs is not None else event.items
|
||||||
|
|
||||||
requires_seat = Exists(
|
requires_seat = Exists(
|
||||||
@@ -139,8 +140,9 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
|
|||||||
items = items.filter(category_id__in=[a for a in filter_categories if a.isdigit()])
|
items = items.filter(category_id__in=[a for a in filter_categories if a.isdigit()])
|
||||||
|
|
||||||
display_add_to_cart = False
|
display_add_to_cart = False
|
||||||
external_quota_cache = quota_cache or event.cache.get('item_quota_cache')
|
quota_cache_key = f'item_quota_cache:{subevent.id if subevent else 0}:{channel}:{bool(require_seat)}'
|
||||||
quota_cache = external_quota_cache or {}
|
quota_cache = quota_cache or event.cache.get(quota_cache_key) or {}
|
||||||
|
quota_cache_existed = bool(quota_cache)
|
||||||
|
|
||||||
if subevent:
|
if subevent:
|
||||||
item_price_override = subevent.item_price_overrides
|
item_price_override = subevent.item_price_overrides
|
||||||
@@ -159,11 +161,11 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
|
|||||||
if item.has_variations:
|
if item.has_variations:
|
||||||
for v in item.available_variations:
|
for v in item.available_variations:
|
||||||
for q in v._subevent_quotas:
|
for q in v._subevent_quotas:
|
||||||
if q not in quota_cache:
|
if q.pk not in quota_cache:
|
||||||
quotas_to_compute.append(q)
|
quotas_to_compute.append(q)
|
||||||
else:
|
else:
|
||||||
for q in item._subevent_quotas:
|
for q in item._subevent_quotas:
|
||||||
if q not in quota_cache:
|
if q.pk not in quota_cache:
|
||||||
quotas_to_compute.append(q)
|
quotas_to_compute.append(q)
|
||||||
|
|
||||||
if quotas_to_compute:
|
if quotas_to_compute:
|
||||||
@@ -306,8 +308,8 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
|
|||||||
|
|
||||||
item._remove = not bool(item.available_variations)
|
item._remove = not bool(item.available_variations)
|
||||||
|
|
||||||
if not external_quota_cache and not voucher and not allow_addons:
|
if not quota_cache_existed and not voucher and not allow_addons and not base_qs_set and not filter_items and not filter_categories:
|
||||||
event.cache.set('item_quota_cache', quota_cache, 5)
|
event.cache.set(quota_cache_key, quota_cache, 5)
|
||||||
items = [item for item in items
|
items = [item for item in items
|
||||||
if (len(item.available_variations) > 0 or not item.has_variations) and not item._remove]
|
if (len(item.available_variations) > 0 or not item.has_variations) and not item._remove]
|
||||||
return items, display_add_to_cart
|
return items, display_add_to_cart
|
||||||
@@ -406,20 +408,40 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
context['ev'] = self.subevent or self.request.event
|
context['ev'] = self.subevent or self.request.event
|
||||||
context['subevent'] = self.subevent
|
context['subevent'] = self.subevent
|
||||||
context['cart'] = self.get_cart()
|
context['cart'] = self.get_cart()
|
||||||
context['has_addon_choices'] = get_cart(self.request).filter(item__addons__isnull=False).exists()
|
context['has_addon_choices'] = any(cp.has_addon_choices for cp in get_cart(self.request))\
|
||||||
|
|
||||||
if self.subevent:
|
if self.subevent:
|
||||||
context['frontpage_text'] = str(self.subevent.frontpage_text)
|
context['frontpage_text'] = str(self.subevent.frontpage_text)
|
||||||
else:
|
else:
|
||||||
context['frontpage_text'] = str(self.request.event.settings.frontpage_text)
|
context['frontpage_text'] = str(self.request.event.settings.frontpage_text)
|
||||||
|
|
||||||
|
if self.request.event.has_subevents:
|
||||||
|
context.update(self._subevent_list_context())
|
||||||
|
|
||||||
|
context['show_cart'] = (
|
||||||
|
context['cart']['positions'] and (
|
||||||
|
self.request.event.has_subevents or self.request.event.presale_is_running
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self.request.event.settings.redirect_to_checkout_directly:
|
||||||
|
context['cart_redirect'] = eventreverse(self.request.event, 'presale:event.checkout.start',
|
||||||
|
kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''})
|
||||||
|
if context['cart_redirect'].startswith('https:'):
|
||||||
|
context['cart_redirect'] = '/' + context['cart_redirect'].split('/', 3)[3]
|
||||||
|
else:
|
||||||
|
context['cart_redirect'] = self.request.path
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def _subevent_list_context(self):
|
||||||
|
context = {}
|
||||||
context['list_type'] = self.request.GET.get("style", self.request.event.settings.event_list_type)
|
context['list_type'] = self.request.GET.get("style", self.request.event.settings.event_list_type)
|
||||||
if context['list_type'] not in ("calendar", "week") and self.request.event.subevents.filter(date_from__gt=now()).count() > 50:
|
if context['list_type'] not in ("calendar", "week") and self.request.event.subevents.filter(date_from__gt=now()).count() > 50:
|
||||||
if self.request.event.settings.event_list_type not in ("calendar", "week"):
|
if self.request.event.settings.event_list_type not in ("calendar", "week"):
|
||||||
self.request.event.settings.event_list_type = "calendar"
|
self.request.event.settings.event_list_type = "calendar"
|
||||||
context['list_type'] = "calendar"
|
context['list_type'] = "calendar"
|
||||||
|
|
||||||
if context['list_type'] == "calendar" and self.request.event.has_subevents:
|
if context['list_type'] == "calendar":
|
||||||
self._set_month_year()
|
self._set_month_year()
|
||||||
tz = pytz.timezone(self.request.event.settings.timezone)
|
tz = pytz.timezone(self.request.event.settings.timezone)
|
||||||
_, ndays = calendar.monthrange(self.year, self.month)
|
_, ndays = calendar.monthrange(self.year, self.month)
|
||||||
@@ -434,7 +456,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
add_subevents_for_days(
|
add_subevents_for_days(
|
||||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
||||||
before, after, ebd, set(), self.request.event,
|
before, after, ebd, set(), self.request.event,
|
||||||
kwargs.get('cart_namespace')
|
self.kwargs.get('cart_namespace')
|
||||||
)
|
)
|
||||||
|
|
||||||
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
||||||
@@ -443,7 +465,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
context['weeks'] = weeks_for_template(ebd, self.year, self.month)
|
context['weeks'] = weeks_for_template(ebd, self.year, self.month)
|
||||||
context['months'] = [date(self.year, i + 1, 1) for i in range(12)]
|
context['months'] = [date(self.year, i + 1, 1) for i in range(12)]
|
||||||
context['years'] = range(now().year - 2, now().year + 3)
|
context['years'] = range(now().year - 2, now().year + 3)
|
||||||
elif context['list_type'] == "week" and self.request.event.has_subevents:
|
elif context['list_type'] == "week":
|
||||||
self._set_week_year()
|
self._set_week_year()
|
||||||
tz = pytz.timezone(self.request.event.settings.timezone)
|
tz = pytz.timezone(self.request.event.settings.timezone)
|
||||||
week = isoweek.Week(self.year, self.week)
|
week = isoweek.Week(self.year, self.week)
|
||||||
@@ -462,7 +484,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
add_subevents_for_days(
|
add_subevents_for_days(
|
||||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
||||||
before, after, ebd, set(), self.request.event,
|
before, after, ebd, set(), self.request.event,
|
||||||
kwargs.get('cart_namespace')
|
self.kwargs.get('cart_namespace')
|
||||||
)
|
)
|
||||||
|
|
||||||
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
||||||
@@ -477,24 +499,10 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
context['week_format'] = get_format('WEEK_FORMAT')
|
context['week_format'] = get_format('WEEK_FORMAT')
|
||||||
if context['week_format'] == 'WEEK_FORMAT':
|
if context['week_format'] == 'WEEK_FORMAT':
|
||||||
context['week_format'] = WEEK_FORMAT
|
context['week_format'] = WEEK_FORMAT
|
||||||
elif self.request.event.has_subevents:
|
else:
|
||||||
context['subevent_list'] = self.request.event.subevents_sorted(
|
context['subevent_list'] = self.request.event.subevents_sorted(
|
||||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request)
|
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request)
|
||||||
)
|
)
|
||||||
|
|
||||||
context['show_cart'] = (
|
|
||||||
context['cart']['positions'] and (
|
|
||||||
self.request.event.has_subevents or self.request.event.presale_is_running
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if self.request.event.settings.redirect_to_checkout_directly:
|
|
||||||
context['cart_redirect'] = eventreverse(self.request.event, 'presale:event.checkout.start',
|
|
||||||
kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''})
|
|
||||||
if context['cart_redirect'].startswith('https:'):
|
|
||||||
context['cart_redirect'] = '/' + context['cart_redirect'].split('/', 3)[3]
|
|
||||||
else:
|
|
||||||
context['cart_redirect'] = self.request.path
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -245,6 +245,8 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TicketPageMixin,
|
|||||||
).exclude(
|
).exclude(
|
||||||
provider__in=('offsetting', 'reseller', 'boxoffice', 'manual')
|
provider__in=('offsetting', 'reseller', 'boxoffice', 'manual')
|
||||||
)
|
)
|
||||||
|
ctx['user_change_allowed'] = self.order.user_change_allowed
|
||||||
|
ctx['user_cancel_allowed'] = self.order.user_cancel_allowed
|
||||||
for r in ctx['refunds']:
|
for r in ctx['refunds']:
|
||||||
if r.provider == 'giftcard':
|
if r.provider == 'giftcard':
|
||||||
gc = GiftCard.objects.get(pk=r.info_data.get('gift_card'))
|
gc = GiftCard.objects.get(pk=r.info_data.get('gift_card'))
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
from django.db.models import Prefetch
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
from pretix.base.models import Question, QuestionAnswer, QuestionOption
|
|
||||||
from pretix.base.views.mixins import BaseQuestionsViewMixin
|
from pretix.base.views.mixins import BaseQuestionsViewMixin
|
||||||
from pretix.presale.forms.checkout import QuestionsForm
|
from pretix.presale.forms.checkout import QuestionsForm
|
||||||
from pretix.presale.views import get_cart
|
from pretix.presale.views import get_cart
|
||||||
@@ -13,27 +11,5 @@ class QuestionsViewMixin(BaseQuestionsViewMixin):
|
|||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def _positions_for_questions(self):
|
def _positions_for_questions(self):
|
||||||
qqs = self.request.event.questions.all()
|
cart = get_cart(self.request)
|
||||||
if self.only_user_visible:
|
|
||||||
qqs = qqs.filter(ask_during_checkin=False, hidden=False)
|
|
||||||
cart = get_cart(self.request).select_related(
|
|
||||||
'addon_to'
|
|
||||||
).prefetch_related(
|
|
||||||
'addons', 'addons__item', 'addons__variation',
|
|
||||||
Prefetch('answers',
|
|
||||||
QuestionAnswer.objects.prefetch_related('options'),
|
|
||||||
to_attr='answerlist'),
|
|
||||||
Prefetch('item__questions',
|
|
||||||
qqs.prefetch_related(
|
|
||||||
Prefetch('options', QuestionOption.objects.prefetch_related(Prefetch(
|
|
||||||
# This prefetch statement is utter bullshit, but it actually prevents Django from doing
|
|
||||||
# a lot of queries since ModelChoiceIterator stops trying to be clever once we have
|
|
||||||
# a prefetch lookup on this query...
|
|
||||||
'question',
|
|
||||||
Question.objects.none(),
|
|
||||||
to_attr='dummy'
|
|
||||||
)))
|
|
||||||
).select_related('dependency_question'),
|
|
||||||
to_attr='questions_to_ask')
|
|
||||||
)
|
|
||||||
return sorted(list(cart), key=self._keyfunc)
|
return sorted(list(cart), key=self._keyfunc)
|
||||||
|
|||||||
Reference in New Issue
Block a user