Ticket #15819: non-unique-related-fields-distinct1.diff
File non-unique-related-fields-distinct1.diff, 5.0 KB (added by , 14 years ago) |
---|
-
django/contrib/admin/views/main.py
169 169 def get_query_set(self): 170 170 use_distinct = False 171 171 172 def field_needs_distinct(field): 173 if ((hasattr(field, 'rel') and 174 isinstance(field.rel, models.ManyToManyRel)) or 175 (isinstance(field, models.related.RelatedObject) and 176 not field.field.unique)): 177 return True 178 return False 179 172 180 qs = self.root_query_set 173 181 lookup_params = self.params.copy() # a dictionary of the query string 174 182 for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR, TO_FIELD_VAR): … … 189 197 f = self.lookup_opts.get_field_by_name(field_name)[0] 190 198 except models.FieldDoesNotExist: 191 199 raise IncorrectLookupParameters 192 if hasattr(f, 'rel') and isinstance(f.rel, models.ManyToManyRel): 193 use_distinct = True 200 use_distinct = field_needs_distinct(f) 194 201 195 202 # if key ends with __in, split parameter into separate values 196 203 if key.endswith('__in'): … … 264 271 for search_spec in orm_lookups: 265 272 field_name = search_spec.split('__', 1)[0] 266 273 f = self.lookup_opts.get_field_by_name(field_name)[0] 267 if hasattr(f, 'rel') and isinstance(f.rel, models.ManyToManyRel):274 if field_needs_distinct(f): 268 275 use_distinct = True 269 276 break 270 277 -
tests/regressiontests/admin_changelist/tests.py
1 1 from django.contrib import admin 2 2 from django.contrib.admin.options import IncorrectLookupParameters 3 from django.contrib.admin.views.main import ChangeList 3 from django.contrib.admin.views.main import ChangeList, SEARCH_VAR 4 4 from django.core.paginator import Paginator 5 5 from django.template import Context, Template 6 6 from django.test import TransactionTestCase … … 223 223 # There's only one ChordsBand instance 224 224 self.assertEqual(cl.result_count, 1) 225 225 226 def test_distinct_for_non_unique_related_object_in_list_filter(self): 227 """ 228 Regressions tests for #15819: Results shouldn't appear more than 229 once for relationships like a non-unique foreign key. 230 """ 231 parent = Parent.objects.create(name='Mary') 232 # Two children with the same name 233 Child.objects.create(parent=parent, name='Daniel') 234 Child.objects.create(parent=parent, name='Daniel') 235 236 m = ParentAdmin(Parent, admin.site) 237 238 request = MockParentFilterRequest('child__name', 'Daniel') 239 cl = ChangeList(request, Parent, m.list_display, m.list_display_links, 240 m.list_filter, m.date_hierarchy, m.search_fields, 241 m.list_select_related, m.list_per_page, 242 m.list_editable, m) 243 244 # Make sure distinct() was called 245 self.assertEqual(cl.query_set.count(), 1) 246 247 def test_distinct_for_non_unique_related_object_in_search_fields(self): 248 """ 249 Regressions tests for #15819: Results shouldn't appear more than 250 once for relationships like a non-unique foreign key. 251 """ 252 parent = Parent.objects.create(name='Mary') 253 Child.objects.create(parent=parent, name='Danielle') 254 Child.objects.create(parent=parent, name='Daniel') 255 256 m = ParentAdmin(Parent, admin.site) 257 258 request = MockParentSearchRequest('daniel') 259 cl = ChangeList(request, Parent, m.list_display, m.list_display_links, 260 m.list_filter, m.date_hierarchy, m.search_fields, 261 m.list_select_related, m.list_per_page, 262 m.list_editable, m) 263 264 # Make sure distinct() was called 265 self.assertEqual(cl.query_set.count(), 1) 266 226 267 def test_pagination(self): 227 268 """ 228 269 Regression tests for #12893: Pagination in admins changelist doesn't … … 254 295 self.assertEqual(cl.paginator.page_range, [1, 2, 3]) 255 296 256 297 298 class ParentAdmin(admin.ModelAdmin): 299 list_filter = ['child__name'] 300 search_fields = ['child__name'] 301 302 257 303 class ChildAdmin(admin.ModelAdmin): 258 304 list_display = ['name', 'parent'] 259 305 list_per_page = 10 … … 295 341 class MockFilteredRequestB(object): 296 342 def __init__(self, pk): 297 343 self.GET = { 'members': pk } 344 345 class MockParentFilterRequest(object): 346 def __init__(self, filter, q): 347 self.GET = {filter: q} 348 349 class MockParentSearchRequest(object): 350 def __init__(self, q): 351 self.GET = {SEARCH_VAR: q}