1 | Index: 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 |
|
---|
38 | Index: 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')
|
---|
83 | Index: 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 |
|
---|
119 | Index: 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.
|
---|
158 | Index: 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 | }
|
---|
185 | Index: 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 |
|
---|