Skip to content

Commit 4b747c6

Browse files
committed
Use subquery to remove duplicates in SearchFilter
1 parent 8dd4250 commit 4b747c6

File tree

2 files changed

+7
-14
lines changed

2 files changed

+7
-14
lines changed

rest_framework/compat.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
versions of Django/Python, and compatibility wrappers around optional packages.
44
"""
55
import django
6-
from django.conf import settings
76
from django.views.generic import View
87

98

@@ -14,13 +13,6 @@ def unicode_http_header(value):
1413
return value
1514

1615

17-
def distinct(queryset, base):
18-
if settings.DATABASES[queryset.db]["ENGINE"] == "django.db.backends.oracle":
19-
# distinct analogue for Oracle users
20-
return base.filter(pk__in=set(queryset.values_list('pk', flat=True)))
21-
return queryset.distinct()
22-
23-
2416
# django.contrib.postgres requires psycopg2
2517
try:
2618
from django.contrib.postgres import fields as postgres_fields

rest_framework/filters.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from django.utils.translation import gettext_lazy as _
1515

1616
from rest_framework import RemovedInDRF317Warning
17-
from rest_framework.compat import coreapi, coreschema, distinct
17+
from rest_framework.compat import coreapi, coreschema
1818
from rest_framework.settings import api_settings
1919

2020

@@ -127,12 +127,13 @@ def filter_queryset(self, request, queryset, view):
127127
conditions.append(reduce(operator.or_, queries))
128128
queryset = queryset.filter(reduce(operator.and_, conditions))
129129

130+
# Remove duplicates from results, if necessary
130131
if self.must_call_distinct(queryset, search_fields):
131-
# Filtering against a many-to-many field requires us to
132-
# call queryset.distinct() in order to avoid duplicate items
133-
# in the resulting queryset.
134-
# We try to avoid this if possible, for performance reasons.
135-
queryset = distinct(queryset, base)
132+
# inspired by django.contrib.admin
133+
# this is more accurate than .distinct form M2M relationship
134+
# also is cross-database
135+
queryset = queryset.filter(pk=models.OuterRef('pk'))
136+
queryset = base.filter(models.Exists(queryset))
136137
return queryset
137138

138139
def to_html(self, request, queryset, view):

0 commit comments

Comments
 (0)