diff options
| author | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-04-26 09:22:46 +0200 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-04-27 10:39:55 +0200 |
| commit | 34981f399a68b633682e0f6a3ded2e31ffd6d243 (patch) | |
| tree | 697d788e86de40d9bd623e8ccc09c4cfcfc28557 /django | |
| parent | fbea64b8ce6a82dd34b1f78cb884306455106185 (diff) | |
[3.2.x] Fixed #32682 -- Made admin changelist use Exists() instead of distinct() for preventing duplicates.
Thanks Zain Patel for the report and Simon Charette for reviews.
The exception introduced in 6307c3f1a123f5975c73b231e8ac4f115fd72c0d
revealed a possible data loss issue in the admin.
Backport of 187118203197801c6cb72dc8b06b714b23b6dd3d from main
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/admin/views/main.py | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index dc43e7849d..a54ef25f23 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -17,7 +17,7 @@ from django.core.exceptions import ( FieldDoesNotExist, ImproperlyConfigured, SuspiciousOperation, ) from django.core.paginator import InvalidPage -from django.db.models import F, Field, ManyToOneRel, OrderBy +from django.db.models import Exists, F, Field, ManyToOneRel, OrderBy, OuterRef from django.db.models.expressions import Combinable from django.urls import reverse from django.utils.http import urlencode @@ -472,13 +472,6 @@ class ChangeList: # ValueError, ValidationError, or ?. raise IncorrectLookupParameters(e) - if not qs.query.select_related: - qs = self.apply_select_related(qs) - - # Set ordering. - ordering = self.get_ordering(request, qs) - qs = qs.order_by(*ordering) - # Apply search results qs, search_may_have_duplicates = self.model_admin.get_search_results( request, qs, self.query, @@ -491,9 +484,17 @@ class ChangeList: ) # Remove duplicates from results, if necessary if filters_may_have_duplicates | search_may_have_duplicates: - return qs.distinct() - else: - return qs + qs = qs.filter(pk=OuterRef('pk')) + qs = self.root_queryset.filter(Exists(qs)) + + # Set ordering. + ordering = self.get_ordering(request, qs) + qs = qs.order_by(*ordering) + + if not qs.query.select_related: + qs = self.apply_select_related(qs) + + return qs def apply_select_related(self, qs): if self.list_select_related is True: |
