|
@@ -4,19 +4,25 @@ from django.contrib.admin.views.main import ChangeList, SEARCH_VAR
|
|
|
from django.core.paginator import Paginator
|
|
|
from django.template import Context, Template
|
|
|
from django.test import TransactionTestCase
|
|
|
+from django.test.client import RequestFactory
|
|
|
+from django.contrib.auth.models import User
|
|
|
|
|
|
from models import (Child, Parent, Genre, Band, Musician, Group, Quartet,
|
|
|
Membership, ChordsMusician, ChordsBand, Invitation)
|
|
|
|
|
|
|
|
|
class ChangeListTests(TransactionTestCase):
|
|
|
+ def setUp(self):
|
|
|
+ self.factory = RequestFactory()
|
|
|
+
|
|
|
def test_select_related_preserved(self):
|
|
|
"""
|
|
|
Regression test for #10348: ChangeList.get_query_set() shouldn't
|
|
|
overwrite a custom select_related provided by ModelAdmin.queryset().
|
|
|
"""
|
|
|
m = ChildAdmin(Child, admin.site)
|
|
|
- cl = ChangeList(MockRequest(), Child, m.list_display, m.list_display_links,
|
|
|
+ request = self.factory.get('/child/')
|
|
|
+ cl = ChangeList(request, Child, m.list_display, m.list_display_links,
|
|
|
m.list_filter, m.date_hierarchy, m.search_fields,
|
|
|
m.list_select_related, m.list_per_page, m.list_editable, m)
|
|
|
self.assertEqual(cl.query_set.query.select_related, {'parent': {'name': {}}})
|
|
@@ -27,7 +33,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
for relationship fields
|
|
|
"""
|
|
|
new_child = Child.objects.create(name='name', parent=None)
|
|
|
- request = MockRequest()
|
|
|
+ request = self.factory.get('/child/')
|
|
|
m = ChildAdmin(Child, admin.site)
|
|
|
cl = ChangeList(request, Child, m.list_display, m.list_display_links,
|
|
|
m.list_filter, m.date_hierarchy, m.search_fields,
|
|
@@ -40,7 +46,6 @@ class ChangeListTests(TransactionTestCase):
|
|
|
self.assertFalse(table_output.find(row_html) == -1,
|
|
|
'Failed to find expected row element: %s' % table_output)
|
|
|
|
|
|
-
|
|
|
def test_result_list_html(self):
|
|
|
"""
|
|
|
Verifies that inclusion tag result_list generates a table when with
|
|
@@ -48,7 +53,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
"""
|
|
|
new_parent = Parent.objects.create(name='parent')
|
|
|
new_child = Child.objects.create(name='name', parent=new_parent)
|
|
|
- request = MockRequest()
|
|
|
+ request = self.factory.get('/child/')
|
|
|
m = ChildAdmin(Child, admin.site)
|
|
|
cl = ChangeList(request, Child, m.list_display, m.list_display_links,
|
|
|
m.list_filter, m.date_hierarchy, m.search_fields,
|
|
@@ -72,7 +77,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
"""
|
|
|
new_parent = Parent.objects.create(name='parent')
|
|
|
new_child = Child.objects.create(name='name', parent=new_parent)
|
|
|
- request = MockRequest()
|
|
|
+ request = self.factory.get('/child/')
|
|
|
m = ChildAdmin(Child, admin.site)
|
|
|
|
|
|
# Test with list_editable fields
|
|
@@ -104,8 +109,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
new_parent = Parent.objects.create(name='parent')
|
|
|
for i in range(200):
|
|
|
new_child = Child.objects.create(name='name %s' % i, parent=new_parent)
|
|
|
- request = MockRequest()
|
|
|
- request.GET['p'] = -1 # Anything outside range
|
|
|
+ request = self.factory.get('/child/', data={'p': -1}) # Anything outside range
|
|
|
m = ChildAdmin(Child, admin.site)
|
|
|
|
|
|
# Test with list_editable fields
|
|
@@ -122,7 +126,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
for i in range(200):
|
|
|
new_child = Child.objects.create(name='name %s' % i, parent=new_parent)
|
|
|
|
|
|
- request = MockRequest()
|
|
|
+ request = self.factory.get('/child/')
|
|
|
m = ChildAdmin(Child, admin.site)
|
|
|
m.list_display = ['id', 'name', 'parent']
|
|
|
m.list_display_links = ['id']
|
|
@@ -148,7 +152,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
band.genres.add(blues)
|
|
|
|
|
|
m = BandAdmin(Band, admin.site)
|
|
|
- request = MockFilterRequest('genres', blues.pk)
|
|
|
+ request = self.factory.get('/band/', data={'genres': blues.pk})
|
|
|
|
|
|
cl = ChangeList(request, Band, m.list_display,
|
|
|
m.list_display_links, m.list_filter, m.date_hierarchy,
|
|
@@ -171,7 +175,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
Membership.objects.create(group=band, music=lead, role='bass player')
|
|
|
|
|
|
m = GroupAdmin(Group, admin.site)
|
|
|
- request = MockFilterRequest('members', lead.pk)
|
|
|
+ request = self.factory.get('/group/', data={'members': lead.pk})
|
|
|
|
|
|
cl = ChangeList(request, Group, m.list_display,
|
|
|
m.list_display_links, m.list_filter, m.date_hierarchy,
|
|
@@ -195,7 +199,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
Membership.objects.create(group=four, music=lead, role='guitar player')
|
|
|
|
|
|
m = QuartetAdmin(Quartet, admin.site)
|
|
|
- request = MockFilterRequest('members', lead.pk)
|
|
|
+ request = self.factory.get('/quartet/', data={'members': lead.pk})
|
|
|
|
|
|
cl = ChangeList(request, Quartet, m.list_display,
|
|
|
m.list_display_links, m.list_filter, m.date_hierarchy,
|
|
@@ -219,7 +223,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
Invitation.objects.create(band=three, player=lead, instrument='bass')
|
|
|
|
|
|
m = ChordsBandAdmin(ChordsBand, admin.site)
|
|
|
- request = MockFilterRequest('members', lead.pk)
|
|
|
+ request = self.factory.get('/chordsband/', data={'members': lead.pk})
|
|
|
|
|
|
cl = ChangeList(request, ChordsBand, m.list_display,
|
|
|
m.list_display_links, m.list_filter, m.date_hierarchy,
|
|
@@ -242,7 +246,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
Child.objects.create(parent=parent, name='Daniel')
|
|
|
|
|
|
m = ParentAdmin(Parent, admin.site)
|
|
|
- request = MockFilterRequest('child__name', 'Daniel')
|
|
|
+ request = self.factory.get('/parent/', data={'child__name': 'Daniel'})
|
|
|
|
|
|
cl = ChangeList(request, Parent, m.list_display, m.list_display_links,
|
|
|
m.list_filter, m.date_hierarchy, m.search_fields,
|
|
@@ -262,7 +266,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
Child.objects.create(parent=parent, name='Daniel')
|
|
|
|
|
|
m = ParentAdmin(Parent, admin.site)
|
|
|
- request = MockSearchRequest('daniel')
|
|
|
+ request = self.factory.get('/parent/', data={SEARCH_VAR: 'daniel'})
|
|
|
|
|
|
cl = ChangeList(request, Parent, m.list_display, m.list_display_links,
|
|
|
m.list_filter, m.date_hierarchy, m.search_fields,
|
|
@@ -282,7 +286,7 @@ class ChangeListTests(TransactionTestCase):
|
|
|
Child.objects.create(name='name %s' % i, parent=parent)
|
|
|
Child.objects.create(name='filtered %s' % i, parent=parent)
|
|
|
|
|
|
- request = MockRequest()
|
|
|
+ request = self.factory.get('/child/')
|
|
|
|
|
|
# Test default queryset
|
|
|
m = ChildAdmin(Child, admin.site)
|
|
@@ -302,6 +306,51 @@ class ChangeListTests(TransactionTestCase):
|
|
|
self.assertEqual(cl.paginator.count, 30)
|
|
|
self.assertEqual(cl.paginator.page_range, [1, 2, 3])
|
|
|
|
|
|
+ def test_dynamic_list_display(self):
|
|
|
+ """
|
|
|
+ Regression tests for #14206: dynamic list_display support.
|
|
|
+ """
|
|
|
+ parent = Parent.objects.create(name='parent')
|
|
|
+ for i in range(10):
|
|
|
+ Child.objects.create(name='child %s' % i, parent=parent)
|
|
|
+
|
|
|
+ user_noparents = User.objects.create(
|
|
|
+ username='noparents',
|
|
|
+ is_superuser=True)
|
|
|
+ user_parents = User.objects.create(
|
|
|
+ username='parents',
|
|
|
+ is_superuser=True)
|
|
|
+
|
|
|
+ def _mocked_authenticated_request(user):
|
|
|
+ request = self.factory.get('/child/')
|
|
|
+ request.user = user
|
|
|
+ return request
|
|
|
+
|
|
|
+ # Test with user 'noparents'
|
|
|
+ m = DynamicListDisplayChildAdmin(Child, admin.site)
|
|
|
+ request = _mocked_authenticated_request(user_noparents)
|
|
|
+ response = m.changelist_view(request)
|
|
|
+ # XXX - Calling render here to avoid ContentNotRenderedError to be
|
|
|
+ # raised. Ticket #15826 should fix this but it's not yet integrated.
|
|
|
+ response.render()
|
|
|
+ self.assertNotContains(response, 'Parent object')
|
|
|
+
|
|
|
+ # Test with user 'parents'
|
|
|
+ m = DynamicListDisplayChildAdmin(Child, admin.site)
|
|
|
+ request = _mocked_authenticated_request(user_parents)
|
|
|
+ response = m.changelist_view(request)
|
|
|
+ # XXX - #15826
|
|
|
+ response.render()
|
|
|
+ self.assertContains(response, 'Parent object')
|
|
|
+
|
|
|
+ # Test default implementation
|
|
|
+ m = ChildAdmin(Child, admin.site)
|
|
|
+ request = _mocked_authenticated_request(user_noparents)
|
|
|
+ response = m.changelist_view(request)
|
|
|
+ # XXX - #15826
|
|
|
+ response.render()
|
|
|
+ self.assertContains(response, 'Parent object')
|
|
|
+
|
|
|
|
|
|
class ParentAdmin(admin.ModelAdmin):
|
|
|
list_filter = ['child__name']
|
|
@@ -311,18 +360,19 @@ class ParentAdmin(admin.ModelAdmin):
|
|
|
class ChildAdmin(admin.ModelAdmin):
|
|
|
list_display = ['name', 'parent']
|
|
|
list_per_page = 10
|
|
|
+
|
|
|
def queryset(self, request):
|
|
|
return super(ChildAdmin, self).queryset(request).select_related("parent__name")
|
|
|
|
|
|
+
|
|
|
class FilteredChildAdmin(admin.ModelAdmin):
|
|
|
list_display = ['name', 'parent']
|
|
|
list_per_page = 10
|
|
|
+
|
|
|
def queryset(self, request):
|
|
|
return super(FilteredChildAdmin, self).queryset(request).filter(
|
|
|
name__contains='filtered')
|
|
|
|
|
|
-class MockRequest(object):
|
|
|
- GET = {}
|
|
|
|
|
|
class CustomPaginator(Paginator):
|
|
|
def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True):
|
|
@@ -333,19 +383,25 @@ class CustomPaginator(Paginator):
|
|
|
class BandAdmin(admin.ModelAdmin):
|
|
|
list_filter = ['genres']
|
|
|
|
|
|
+
|
|
|
class GroupAdmin(admin.ModelAdmin):
|
|
|
list_filter = ['members']
|
|
|
|
|
|
+
|
|
|
class QuartetAdmin(admin.ModelAdmin):
|
|
|
list_filter = ['members']
|
|
|
|
|
|
+
|
|
|
class ChordsBandAdmin(admin.ModelAdmin):
|
|
|
list_filter = ['members']
|
|
|
|
|
|
-class MockFilterRequest(object):
|
|
|
- def __init__(self, filter, q):
|
|
|
- self.GET = {filter: q}
|
|
|
|
|
|
-class MockSearchRequest(object):
|
|
|
- def __init__(self, q):
|
|
|
- self.GET = {SEARCH_VAR: q}
|
|
|
+class DynamicListDisplayChildAdmin(admin.ModelAdmin):
|
|
|
+ list_display = ('name', 'parent')
|
|
|
+
|
|
|
+ def get_list_display(self, request):
|
|
|
+ my_list_display = list(self.list_display)
|
|
|
+ if request.user.username == 'noparents':
|
|
|
+ my_list_display.remove('parent')
|
|
|
+
|
|
|
+ return my_list_display
|