Code

Ticket #9749: patch_django_9749.20090317.diff

File patch_django_9749.20090317.diff, 8.4 KB (added by david, 5 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