Code

Ticket #15819: non-unique-related-fields-distinct2.diff

File non-unique-related-fields-distinct2.diff, 6.0 KB (added by ryankask, 3 years ago)
Line 
1Index: regressiontests/admin_changelist/tests.py
2===================================================================
3--- regressiontests/admin_changelist/tests.py   (revision 16061)
4+++ regressiontests/admin_changelist/tests.py   (working copy)
5@@ -1,6 +1,6 @@
6 from django.contrib import admin
7 from django.contrib.admin.options import IncorrectLookupParameters
8-from django.contrib.admin.views.main import ChangeList
9+from django.contrib.admin.views.main import ChangeList, SEARCH_VAR
10 from django.core.paginator import Paginator
11 from django.template import Context, Template
12 from django.test import TransactionTestCase
13@@ -148,12 +148,14 @@
14         band.genres.add(blues)
15 
16         m = BandAdmin(Band, admin.site)
17-        cl = ChangeList(MockFilteredRequestA(blues.pk), Band, m.list_display,
18+        request = MockFilterRequest('genres', blues.pk)
19+
20+        cl = ChangeList(request, Band, m.list_display,
21                 m.list_display_links, m.list_filter, m.date_hierarchy,
22                 m.search_fields, m.list_select_related, m.list_per_page,
23                 m.list_editable, m)
24 
25-        cl.get_results(MockFilteredRequestA(blues.pk))
26+        cl.get_results(request)
27 
28         # There's only one Group instance
29         self.assertEqual(cl.result_count, 1)
30@@ -169,12 +171,14 @@
31         Membership.objects.create(group=band, music=lead, role='bass player')
32 
33         m = GroupAdmin(Group, admin.site)
34-        cl = ChangeList(MockFilteredRequestB(lead.pk), Group, m.list_display,
35+        request = MockFilterRequest('members', lead.pk)
36+
37+        cl = ChangeList(request, Group, m.list_display,
38                 m.list_display_links, m.list_filter, m.date_hierarchy,
39                 m.search_fields, m.list_select_related, m.list_per_page,
40                 m.list_editable, m)
41 
42-        cl.get_results(MockFilteredRequestB(lead.pk))
43+        cl.get_results(request)
44 
45         # There's only one Group instance
46         self.assertEqual(cl.result_count, 1)
47@@ -191,12 +195,14 @@
48         Membership.objects.create(group=four, music=lead, role='guitar player')
49 
50         m = QuartetAdmin(Quartet, admin.site)
51-        cl = ChangeList(MockFilteredRequestB(lead.pk), Quartet, m.list_display,
52+        request = MockFilterRequest('members', lead.pk)
53+
54+        cl = ChangeList(request, Quartet, m.list_display,
55                 m.list_display_links, m.list_filter, m.date_hierarchy,
56                 m.search_fields, m.list_select_related, m.list_per_page,
57                 m.list_editable, m)
58 
59-        cl.get_results(MockFilteredRequestB(lead.pk))
60+        cl.get_results(request)
61 
62         # There's only one Quartet instance
63         self.assertEqual(cl.result_count, 1)
64@@ -213,16 +219,59 @@
65         Invitation.objects.create(band=three, player=lead, instrument='bass')
66 
67         m = ChordsBandAdmin(ChordsBand, admin.site)
68-        cl = ChangeList(MockFilteredRequestB(lead.pk), ChordsBand, m.list_display,
69+        request = MockFilterRequest('members', lead.pk)
70+
71+        cl = ChangeList(request, ChordsBand, m.list_display,
72                 m.list_display_links, m.list_filter, m.date_hierarchy,
73                 m.search_fields, m.list_select_related, m.list_per_page,
74                 m.list_editable, m)
75 
76-        cl.get_results(MockFilteredRequestB(lead.pk))
77+        cl.get_results(request)
78 
79         # There's only one ChordsBand instance
80         self.assertEqual(cl.result_count, 1)
81 
82+    def test_distinct_for_non_unique_related_object_in_list_filter(self):
83+        """
84+        Regressions tests for #15819: Results shouldn't appear more than
85+        once for relationships like a non-unique foreign key.
86+        """
87+        parent = Parent.objects.create(name='Mary')
88+        # Two children with the same name
89+        Child.objects.create(parent=parent, name='Daniel')
90+        Child.objects.create(parent=parent, name='Daniel')
91+
92+        m = ParentAdmin(Parent, admin.site)
93+
94+        request = MockFilterRequest('child__name', 'Daniel')
95+        cl = ChangeList(request, Parent, m.list_display, m.list_display_links,
96+                        m.list_filter, m.date_hierarchy, m.search_fields,
97+                        m.list_select_related, m.list_per_page,
98+                        m.list_editable, m)
99+
100+        # Make sure distinct() was called
101+        self.assertEqual(cl.query_set.count(), 1)
102+
103+    def test_distinct_for_non_unique_related_object_in_search_fields(self):
104+        """
105+        Regressions tests for #15819: Results shouldn't appear more than
106+        once for relationships like a non-unique foreign key.
107+        """
108+        parent = Parent.objects.create(name='Mary')
109+        Child.objects.create(parent=parent, name='Danielle')
110+        Child.objects.create(parent=parent, name='Daniel')
111+
112+        m = ParentAdmin(Parent, admin.site)
113+
114+        request = MockSearchRequest('daniel')
115+        cl = ChangeList(request, Parent, m.list_display, m.list_display_links,
116+                        m.list_filter, m.date_hierarchy, m.search_fields,
117+                        m.list_select_related, m.list_per_page,
118+                        m.list_editable, m)
119+
120+        # Make sure distinct() was called
121+        self.assertEqual(cl.query_set.count(), 1)
122+
123     def test_pagination(self):
124         """
125         Regression tests for #12893: Pagination in admins changelist doesn't
126@@ -254,6 +303,11 @@
127         self.assertEqual(cl.paginator.page_range, [1, 2, 3])
128 
129 
130+class ParentAdmin(admin.ModelAdmin):
131+    list_filter = ['child__name']
132+    search_fields = ['child__name']
133+
134+
135 class ChildAdmin(admin.ModelAdmin):
136     list_display = ['name', 'parent']
137     list_per_page = 10
138@@ -288,10 +342,10 @@
139 class ChordsBandAdmin(admin.ModelAdmin):
140     list_filter = ['members']
141 
142-class MockFilteredRequestA(object):
143-    def __init__(self, pk):
144-        self.GET = { 'genres' : pk }
145+class MockFilterRequest(object):
146+    def __init__(self, filter, q):
147+        self.GET = {filter: q}
148 
149-class MockFilteredRequestB(object):
150-    def __init__(self, pk):
151-        self.GET = { 'members': pk }
152+class MockSearchRequest(object):
153+    def __init__(self, q):
154+        self.GET = {SEARCH_VAR: q}