summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorJulien Phalip <jphalip@gmail.com>2012-03-03 02:13:35 +0000
committerJulien Phalip <jphalip@gmail.com>2012-03-03 02:13:35 +0000
commitd636150e533a2954f9b74aa6ca2e7375b18437ef (patch)
treea3d54a8ff53594b5cfe1812e0101b7192b4af174 /django
parentc76200a0bfbbec747fa420cc6ef21868dcc3bf69 (diff)
Fixed #17198 -- Ensured that a deterministic order is used across all database backends for displaying the admin change list's results. Many thanks to Luke Plant for the report and general approach, to everyone involved in the design discussions, and to Carl Meyer for the patch review. Refs #16819.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17635 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
-rw-r--r--django/contrib/admin/views/main.py35
1 files changed, 26 insertions, 9 deletions
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index 32113f56eb..56f13f8099 100644
--- a/django/contrib/admin/views/main.py
+++ b/django/contrib/admin/views/main.py
@@ -66,7 +66,6 @@ class ChangeList(object):
self.list_editable = ()
else:
self.list_editable = list_editable
- self.ordering = self.get_ordering(request)
self.query = request.GET.get(SEARCH_VAR, '')
self.query_set = self.get_query_set(request)
self.get_results(request)
@@ -218,13 +217,18 @@ class ChangeList(object):
attr = getattr(self.model, field_name)
return getattr(attr, 'admin_order_field', None)
- def get_ordering(self, request):
+ def get_ordering(self, request, queryset):
+ """
+ Returns the list of ordering fields for the change list.
+ First we check the get_ordering() method in model admin, then we check
+ the object's default ordering. Then, any manually-specified ordering
+ from the query string overrides anything. Finally, a deterministic
+ order is guaranteed by ensuring the primary key is used as the last
+ ordering field.
+ """
params = self.params
- # For ordering, first check the if exists the "get_ordering" method
- # in model admin, then check "ordering" parameter in the admin
- # options, then check the object's default ordering. Finally, a
- # manually-specified ordering from the query string overrides anything.
- ordering = self.model_admin.get_ordering(request) or self._get_default_ordering()
+ ordering = list(self.model_admin.get_ordering(request)
+ or self._get_default_ordering())
if ORDER_VAR in params:
# Clear ordering and used params
ordering = []
@@ -239,6 +243,19 @@ class ChangeList(object):
ordering.append(pfx + order_field)
except (IndexError, ValueError):
continue # Invalid ordering specified, skip it.
+
+ # Add the given query's ordering fields, if any.
+ ordering.extend(queryset.query.order_by)
+
+ # Ensure that the primary key is systematically present in the list of
+ # ordering fields so we can guarantee a deterministic order across all
+ # database backends.
+ pk_name = self.lookup_opts.pk.name
+ if not (set(ordering) & set(['pk', '-pk', pk_name, '-' + pk_name])):
+ # The two sets do not intersect, meaning the pk isn't present. So
+ # we add it.
+ ordering.append('pk')
+
return ordering
def get_ordering_field_columns(self):
@@ -322,8 +339,8 @@ class ChangeList(object):
break
# Set ordering.
- if self.ordering:
- qs = qs.order_by(*self.ordering)
+ ordering = self.get_ordering(request, qs)
+ qs = qs.order_by(*ordering)
# Apply keyword searches.
def construct_search(field_name):