mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Ensure total ordering of paginated lists (#3061)
This commit is contained in:
@@ -58,13 +58,15 @@ from pretix.base.models import (
|
||||
Checkin, CheckinList, Device, Event, EventMetaProperty, EventMetaValue,
|
||||
Gate, Invoice, InvoiceAddress, Item, Order, OrderPayment, OrderPosition,
|
||||
OrderRefund, Organizer, Question, QuestionAnswer, SubEvent,
|
||||
SubEventMetaValue, Team, TeamAPIToken, TeamInvite,
|
||||
SubEventMetaValue, Team, TeamAPIToken, TeamInvite, Voucher,
|
||||
)
|
||||
from pretix.base.signals import register_payment_providers
|
||||
from pretix.control.forms.widgets import Select2
|
||||
from pretix.control.signals import order_search_filter_q
|
||||
from pretix.helpers.countries import CachedCountries
|
||||
from pretix.helpers.database import rolledback_transaction
|
||||
from pretix.helpers.database import (
|
||||
get_deterministic_ordering, rolledback_transaction,
|
||||
)
|
||||
from pretix.helpers.dicts import move_to_end
|
||||
from pretix.helpers.i18n import i18ncomp
|
||||
|
||||
@@ -380,7 +382,9 @@ class OrderFilterForm(FilterForm):
|
||||
)
|
||||
|
||||
if fdata.get('ordering'):
|
||||
qs = qs.order_by(self.get_order_by())
|
||||
qs = qs.order_by(*get_deterministic_ordering(Order, self.get_order_by()))
|
||||
else:
|
||||
qs = qs.order_by('-datetime', '-pk')
|
||||
|
||||
if fdata.get('provider'):
|
||||
qs = qs.annotate(
|
||||
@@ -1044,11 +1048,11 @@ class OrderPaymentSearchFilterForm(forms.Form):
|
||||
if fdata.get('ordering'):
|
||||
p = self.cleaned_data.get('ordering')
|
||||
if p.startswith('-') and p not in self.orders:
|
||||
qs = qs.order_by('-' + self.orders[p[1:]])
|
||||
qs = qs.order_by(*get_deterministic_ordering(OrderPayment, '-' + self.orders[p[1:]]))
|
||||
else:
|
||||
qs = qs.order_by(self.orders[p])
|
||||
qs = qs.order_by(*get_deterministic_ordering(OrderPayment, self.orders[p]))
|
||||
else:
|
||||
qs = qs.order_by('-created')
|
||||
qs = qs.order_by('-created', '-pk')
|
||||
|
||||
return qs
|
||||
|
||||
@@ -1226,9 +1230,9 @@ class SubEventFilterForm(FilterForm):
|
||||
qs = qs.filter(f)
|
||||
|
||||
if fdata.get('ordering'):
|
||||
qs = qs.order_by(self.get_order_by())
|
||||
qs = qs.order_by(*get_deterministic_ordering(SubEvent, self.get_order_by()))
|
||||
else:
|
||||
qs = qs.order_by('-date_from')
|
||||
qs = qs.order_by('-date_from', '-pk')
|
||||
|
||||
return qs
|
||||
|
||||
@@ -1462,9 +1466,7 @@ class TeamFilterForm(FilterForm):
|
||||
)
|
||||
|
||||
if fdata.get('ordering'):
|
||||
qs = qs.order_by(self.get_order_by())
|
||||
else:
|
||||
qs = qs.order_by('name')
|
||||
qs = qs.order_by(*get_deterministic_ordering(Team, self.get_order_by()))
|
||||
|
||||
return qs.distinct()
|
||||
|
||||
@@ -1619,7 +1621,7 @@ class EventFilterForm(FilterForm):
|
||||
qs = qs.filter(f)
|
||||
|
||||
if fdata.get('ordering'):
|
||||
qs = qs.order_by(self.get_order_by())
|
||||
qs = qs.order_by(*get_deterministic_ordering(Event, self.get_order_by()))
|
||||
|
||||
return qs
|
||||
|
||||
@@ -1764,11 +1766,11 @@ class CheckinListAttendeeFilterForm(FilterForm):
|
||||
if isinstance(ob, dict):
|
||||
ob = dict(ob)
|
||||
o = ob.pop('_order')
|
||||
qs = qs.annotate(**ob).order_by(o)
|
||||
qs = qs.annotate(**ob).order_by(*get_deterministic_ordering(OrderPosition, [o]))
|
||||
elif isinstance(ob, (list, tuple)):
|
||||
qs = qs.order_by(*ob)
|
||||
qs = qs.order_by(*get_deterministic_ordering(OrderPosition, ob))
|
||||
else:
|
||||
qs = qs.order_by(ob)
|
||||
qs = qs.order_by(*get_deterministic_ordering(OrderPosition, [ob]))
|
||||
|
||||
if fdata.get('item'):
|
||||
qs = qs.filter(item=fdata.get('item'))
|
||||
@@ -2011,11 +2013,11 @@ class VoucherFilterForm(FilterForm):
|
||||
if isinstance(ob, dict):
|
||||
ob = dict(ob)
|
||||
o = ob.pop('_order')
|
||||
qs = qs.annotate(**ob).order_by(o)
|
||||
qs = qs.annotate(**ob).order_by(*get_deterministic_ordering(Voucher, o))
|
||||
elif isinstance(ob, (list, tuple)):
|
||||
qs = qs.order_by(*ob)
|
||||
qs = qs.order_by(*get_deterministic_ordering(Voucher, ob))
|
||||
else:
|
||||
qs = qs.order_by(ob)
|
||||
qs = qs.order_by(*get_deterministic_ordering(Voucher, ob))
|
||||
|
||||
return qs
|
||||
|
||||
@@ -2098,9 +2100,7 @@ class RefundFilterForm(FilterForm):
|
||||
OrderRefund.REFUND_STATE_EXTERNAL])
|
||||
|
||||
if fdata.get('ordering'):
|
||||
qs = qs.order_by(self.get_order_by())
|
||||
else:
|
||||
qs = qs.order_by('-created')
|
||||
qs = qs.order_by(*get_deterministic_ordering(OrderRefund, self.get_order_by()))
|
||||
return qs
|
||||
|
||||
|
||||
|
||||
@@ -447,6 +447,7 @@ class CheckinListView(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
context_object_name = 'checkins'
|
||||
permission = 'can_view_orders'
|
||||
template_name = 'pretixcontrol/checkin/checkins.html'
|
||||
ordering = ('-datetime', '-pk')
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Checkin.all.filter(
|
||||
|
||||
@@ -1061,7 +1061,7 @@ class EventLog(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
def get_queryset(self):
|
||||
qs = self.request.event.logentry_set.all().select_related(
|
||||
'user', 'content_type', 'api_token', 'oauth_application', 'device'
|
||||
).order_by('-datetime')
|
||||
).order_by('-datetime', '-pk')
|
||||
qs = qs.exclude(action_type__in=OVERVIEW_BANLIST)
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'can_view_orders',
|
||||
request=self.request):
|
||||
|
||||
@@ -816,16 +816,18 @@ class QuotaList(PaginationMixin, ListView):
|
||||
qs = qs.filter(subevent_id=s)
|
||||
|
||||
valid_orders = {
|
||||
'-date': ('-subevent__date_from', 'name'),
|
||||
'date': ('subevent__date_from', '-name'),
|
||||
'size': ('size', 'name'),
|
||||
'-size': ('-size', '-name'),
|
||||
'name': ('name',),
|
||||
'-name': ('-name',),
|
||||
'-date': ('-subevent__date_from', 'name', 'pk'),
|
||||
'date': ('subevent__date_from', '-name', '-pk'),
|
||||
'size': ('size', 'name', 'pk'),
|
||||
'-size': ('-size', '-name', '-pk'),
|
||||
'name': ('name', 'pk'),
|
||||
'-name': ('-name', '-pk'),
|
||||
}
|
||||
|
||||
if self.request.GET.get("ordering", "-date") in valid_orders:
|
||||
qs = qs.order_by(*valid_orders[self.request.GET.get("ordering", "-date")])
|
||||
else:
|
||||
qs = qs.order_by('name', 'subevent__date_from', 'pk')
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
@@ -2529,7 +2529,7 @@ class RefundList(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
def get_queryset(self):
|
||||
qs = OrderRefund.objects.filter(
|
||||
order__event=self.request.event
|
||||
).select_related('order')
|
||||
).select_related('order').order_by('-created', '-pk')
|
||||
|
||||
if self.filter_form.is_valid():
|
||||
qs = self.filter_form.filter_qs(qs)
|
||||
|
||||
@@ -556,7 +556,7 @@ class TeamListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, P
|
||||
memcount=Count('members', distinct=True),
|
||||
eventcount=Count('limit_events', distinct=True),
|
||||
invcount=Count('invites', distinct=True)
|
||||
).all().order_by('name')
|
||||
).all().order_by('name', 'pk')
|
||||
if self.filter_form.is_valid():
|
||||
qs = self.filter_form.filter_qs(qs)
|
||||
return qs
|
||||
@@ -2040,6 +2040,8 @@ class LogView(OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
context_object_name = 'logs'
|
||||
|
||||
def get_queryset(self):
|
||||
# technically, we'd also need to sort by pk since this is a paginated list, but in this case we just can't
|
||||
# bear the performance cost
|
||||
qs = self.request.organizer.all_logentries().select_related(
|
||||
'user', 'content_type', 'api_token', 'oauth_application', 'device'
|
||||
).order_by('-datetime')
|
||||
@@ -2437,7 +2439,7 @@ class CustomerDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
q |= Q(email__iexact=self.customer.email)
|
||||
qs = Order.objects.filter(
|
||||
q
|
||||
).select_related('event').order_by('-datetime')
|
||||
).select_related('event').order_by('-datetime', 'pk')
|
||||
return qs
|
||||
|
||||
@cached_property
|
||||
|
||||
Reference in New Issue
Block a user