Ticket #9749: patch_django_9749.20090317.diff

File patch_django_9749.20090317.diff, 8.4 KB (added by David Larlet, 15 years ago)

New patch against r10069 (another bug resolution was conflictual with tests), nothing has changed

Line 
1Index: django/contrib/admin/validation.py
2===================================================================
3--- django/contrib/admin/validation.py (revision 10069)
4+++ django/contrib/admin/validation.py (working copy)
5@@ -5,9 +5,10 @@
6
7 from django.core.exceptions import ImproperlyConfigured
8 from django.db import models
9 from django.forms.models import BaseModelForm, BaseModelFormSet, fields_for_model
10 from django.contrib.admin.options import flatten_fieldsets, BaseModelAdmin
11 from django.contrib.admin.options import HORIZONTAL, VERTICAL
12+from django.contrib.admin.views.main import ChangeList
13
14 __all__ = ['validate']
15
16@@ -117,9 +118,14 @@
17 raise ImproperlyConfigured("'%s.inlines[%d].model' does not "
18 "inherit from models.Model." % (cls.__name__, idx))
19 validate_base(inline, inline.model)
20 validate_inline(inline)
21
22+ # changelist_class = ChangeList
23+ if hasattr(cls, 'changelist_class') and not issubclass(cls.changelist_class, ChangeList):
24+ raise ImproperlyConfigured("'%s.changelist_class' does not inherit "
25+ "from admin.views.main.ChangeList." % cls.__name__)
26+
27 def validate_inline(cls):
28 # model is already verified to exist and be a Model
29 if cls.fk_name: # default value is None
30 f = get_field(cls, cls.model, cls.model._meta, 'fk_name', cls.fk_name)
31@@ -138,6 +144,14 @@
32 raise ImproperlyConfigured("'%s.formset' does not inherit from "
33 "BaseModelFormSet." % cls.__name__)
34
35 def validate_base(cls, model):
36 opts = model._meta
37
38Index: django/contrib/admin/options.py
39===================================================================
40--- django/contrib/admin/options.py (revision 10069)
41+++ django/contrib/admin/options.py (working copy)
42@@ -170,6 +170,9 @@
43
44 class ModelAdmin(BaseModelAdmin):
45 "Encapsulates all admin options and functionality for a given model."
46+ # Avoid circular import of ChangeList
47+ from django.contrib.admin.views.main import ChangeList
48+
49 __metaclass__ = forms.MediaDefiningClass
50
51 list_display = ('__str__',)
52@@ -183,6 +186,7 @@
53 save_on_top = False
54 ordering = None
55 inlines = []
56+ changelist_class = ChangeList
57
58 # Custom templates (designed to be over-ridden in subclasses)
59 change_form_template = None
60@@ -678,13 +682,12 @@
61
62 def changelist_view(self, request, extra_context=None):
63 "The 'change list' admin view for this model."
64- from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
65 opts = self.model._meta
66 app_label = opts.app_label
67 if not self.has_change_permission(request, None):
68 raise PermissionDenied
69 try:
70- cl = ChangeList(request, self.model, self.list_display, self.list_display_links, self.list_filter,
71+ cl = self.changelist_class(request, self.model, self.list_display, self.list_display_links, self.list_filter,
72 self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self)
73 except IncorrectLookupParameters:
74 # Wacky lookup parameters were given, so redirect to the main
75@@ -692,6 +695,7 @@
76 # parameter via the query string. If wacky parameters were given and
77 # the 'invalid=1' parameter was already in the query string, something
78 # is screwed up with the database, so display an error page.
79+ from django.contrib.admin.views.main import ERROR_FLAG
80 if ERROR_FLAG in request.GET.keys():
81 return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
82 return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
83Index: tests/regressiontests/admin_views/tests.py
84===================================================================
85--- tests/regressiontests/admin_views/tests.py (revision 10069)
86+++ tests/regressiontests/admin_views/tests.py (working copy)
87@@ -729,6 +729,31 @@
88 response = self.client.post('/test_admin/admin/admin_views/book/1/delete/', delete_dict)
89 self.assertRedirects(response, '/test_admin/admin/admin_views/book/')
90
91+
92+class AdminCustomChangeListTest(TestCase):
93+ fixtures = ['admin-views-users.xml']
94+
95+ def setUp(self):
96+ self.client.login(username='super', password='secret')
97+
98+ def tearDown(self):
99+ self.client.logout()
100+
101+ def testCustomLinkPresence(self):
102+ """
103+ A test to ensure that custom ChangeList class works as expected.
104+ """
105+ post_data = {
106+ "title": u"Lion",
107+ }
108+ response = self.client.post('/test_admin/admin/admin_views/animal/add/', post_data)
109+ self.failUnlessEqual(response.status_code, 302) # redirect somewhere
110+ response = self.client.get('/test_admin/admin/admin_views/animal/')
111+ self.failUnlessEqual(response.status_code, 200)
112+ should_contain = """<a href="custom/1/">Lion</a>"""
113+ self.assertContains(response, should_contain)
114+
115+
116 class AdminInheritedInlinesTest(TestCase):
117 fixtures = ['admin-views-users.xml',]
118
119Index: tests/regressiontests/admin_views/models.py
120===================================================================
121--- tests/regressiontests/admin_views/models.py (revision 10069)
122+++ tests/regressiontests/admin_views/models.py (working copy)
123@@ -134,6 +134,20 @@
124 class ThingAdmin(admin.ModelAdmin):
125 list_filter = ('color',)
126
127+
128+class Animal(models.Model):
129+ title = models.CharField(max_length=20)
130+ def __unicode__(self):
131+ return self.title
132+
133+class AnimalChangeList(admin.views.main.ChangeList):
134+ def url_for_result(self, result):
135+ return "custom/%s/" % admin.util.quote(getattr(result, self.pk_attname))
136+
137+class AnimalAdmin(admin.ModelAdmin):
138+ changelist_class = AnimalChangeList
139+
140+
141 class Persona(models.Model):
142 """
143 A simple persona associated with accounts, to test inlining of related
144@@ -177,12 +191,14 @@
145 BarAccountAdmin
146 )
147
148 admin.site.register(Article, ArticleAdmin)
149 admin.site.register(CustomArticle, CustomArticleAdmin)
150 admin.site.register(Section, inlines=[ArticleInline])
151 admin.site.register(ModelWithStringPrimaryKey)
152 admin.site.register(Color)
153 admin.site.register(Thing, ThingAdmin)
154+admin.site.register(Animal, AnimalAdmin)
155 admin.site.register(Persona, PersonaAdmin)
156
157 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
158Index: tests/regressiontests/modeladmin/models.py
159===================================================================
160--- tests/regressiontests/modeladmin/models.py (revision 10069)
161+++ tests/regressiontests/modeladmin/models.py (working copy)
162@@ -912,5 +912,22 @@
163 ... inlines = [ValidationTestInline]
164 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
165
166+# changelist_class
167+
168+>>> class ValidationTestModelAdmin(ModelAdmin):
169+... changelist_class = object
170+>>> validate(ValidationTestModelAdmin, ValidationTestModel)
171+Traceback (most recent call last):
172+...
173+ImproperlyConfigured: 'ValidationTestModelAdmin.changelist_class' does not inherit from admin.views.main.ChangeList.
174+
175+>>> from django.contrib.admin.views.main import ChangeList
176+>>> class ValidationTestChangeList(ChangeList):
177+... def url_for_result(self, result):
178+... return "custom/%s/" % quote(getattr(result, self.pk_attname))
179+>>> class ValidationTestModelAdmin(ModelAdmin):
180+... changelist_class = ValidationTestChangeList
181+>>> validate(ValidationTestModelAdmin, ValidationTestModel)
182+
183 """
184 }
185Index: docs/ref/contrib/admin.txt
186===================================================================
187--- docs/ref/contrib/admin.txt (revision 10069)
188+++ docs/ref/contrib/admin.txt (working copy)
189@@ -77,6 +77,26 @@
190 class AuthorAdmin(admin.ModelAdmin):
191 date_hierarchy = 'pub_date'
192
193+``changelist_class``
194+~~~~~~~~~~~~~~~~~~
195+
196+Set ``changelist_class`` to a class which inherits from
197+``admin.views.main.ChangeList``, and the change list page will use this class
198+to render the list.
199+
200+Example::
201+
202+ from django.contrib import admin
203+
204+ class CustomChangeList(admin.views.main.ChangeList):
205+ def url_for_result(self, result):
206+ return "custom/%s/" % admin.util.quote(getattr(result, self.pk_attname))
207+
208+ class AuthorAdmin(admin.ModelAdmin):
209+ date_hierarchy = 'pub_date'
210+ changelist_class = CustomChangeList
211+
212+
213 ``date_hierarchy``
214 ~~~~~~~~~~~~~~~~~~
215
Back to Top