|
0
|
1 |
import re |
|
|
2 |
from django import http, template |
|
|
3 |
from django.contrib.admin import ModelAdmin |
|
|
4 |
from django.contrib.admin import actions |
|
|
5 |
from django.contrib.auth import authenticate, login |
|
|
6 |
from django.db.models.base import ModelBase |
|
|
7 |
from django.core.exceptions import ImproperlyConfigured |
|
|
8 |
from django.core.urlresolvers import reverse |
|
|
9 |
from django.shortcuts import render_to_response |
|
|
10 |
from django.utils.functional import update_wrapper |
|
|
11 |
from django.utils.safestring import mark_safe |
|
|
12 |
from django.utils.text import capfirst |
|
|
13 |
from django.utils.translation import ugettext_lazy, ugettext as _ |
|
|
14 |
from django.views.decorators.cache import never_cache |
|
|
15 |
from django.conf import settings |
|
|
16 |
try: |
|
|
17 |
set |
|
|
18 |
except NameError: |
|
|
19 |
from sets import Set as set # Python 2.3 fallback |
|
|
20 |
|
|
|
21 |
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") |
|
|
22 |
LOGIN_FORM_KEY = 'this_is_the_login_form' |
|
|
23 |
|
|
|
24 |
class AlreadyRegistered(Exception): |
|
|
25 |
pass |
|
|
26 |
|
|
|
27 |
class NotRegistered(Exception): |
|
|
28 |
pass |
|
|
29 |
|
|
|
30 |
class AdminSite(object): |
|
|
31 |
""" |
|
|
32 |
An AdminSite object encapsulates an instance of the Django admin application, ready |
|
|
33 |
to be hooked in to your URLconf. Models are registered with the AdminSite using the |
|
|
34 |
register() method, and the root() method can then be used as a Django view function |
|
|
35 |
that presents a full admin interface for the collection of registered models. |
|
|
36 |
""" |
|
|
37 |
|
|
|
38 |
index_template = None |
|
|
39 |
login_template = None |
|
|
40 |
app_index_template = None |
|
|
41 |
|
|
|
42 |
def __init__(self, name=None, app_name='admin'): |
|
|
43 |
self._registry = {} # model_class class -> admin_class instance |
|
|
44 |
self.root_path = None |
|
|
45 |
if name is None: |
|
|
46 |
self.name = 'admin' |
|
|
47 |
else: |
|
|
48 |
self.name = name |
|
|
49 |
self.app_name = app_name |
|
|
50 |
self._actions = {'delete_selected': actions.delete_selected} |
|
|
51 |
self._global_actions = self._actions.copy() |
|
|
52 |
|
|
|
53 |
def register(self, model_or_iterable, admin_class=None, **options): |
|
|
54 |
""" |
|
|
55 |
Registers the given model(s) with the given admin class. |
|
|
56 |
|
|
|
57 |
The model(s) should be Model classes, not instances. |
|
|
58 |
|
|
|
59 |
If an admin class isn't given, it will use ModelAdmin (the default |
|
|
60 |
admin options). If keyword arguments are given -- e.g., list_display -- |
|
|
61 |
they'll be applied as options to the admin class. |
|
|
62 |
|
|
|
63 |
If a model is already registered, this will raise AlreadyRegistered. |
|
|
64 |
""" |
|
|
65 |
if not admin_class: |
|
|
66 |
admin_class = ModelAdmin |
|
|
67 |
|
|
|
68 |
# Don't import the humongous validation code unless required |
|
|
69 |
if admin_class and settings.DEBUG: |
|
|
70 |
from django.contrib.admin.validation import validate |
|
|
71 |
else: |
|
|
72 |
validate = lambda model, adminclass: None |
|
|
73 |
|
|
|
74 |
if isinstance(model_or_iterable, ModelBase): |
|
|
75 |
model_or_iterable = [model_or_iterable] |
|
|
76 |
for model in model_or_iterable: |
|
|
77 |
if model in self._registry: |
|
|
78 |
raise AlreadyRegistered('The model %s is already registered' % model.__name__) |
|
|
79 |
|
|
|
80 |
# If we got **options then dynamically construct a subclass of |
|
|
81 |
# admin_class with those **options. |
|
|
82 |
if options: |
|
|
83 |
# For reasons I don't quite understand, without a __module__ |
|
|
84 |
# the created class appears to "live" in the wrong place, |
|
|
85 |
# which causes issues later on. |
|
|
86 |
options['__module__'] = __name__ |
|
|
87 |
admin_class = type("%sAdmin" % model.__name__, (admin_class,), options) |
|
|
88 |
|
|
|
89 |
# Validate (which might be a no-op) |
|
|
90 |
validate(admin_class, model) |
|
|
91 |
|
|
|
92 |
# Instantiate the admin class to save in the registry |
|
|
93 |
self._registry[model] = admin_class(model, self) |
|
|
94 |
|
|
|
95 |
def unregister(self, model_or_iterable): |
|
|
96 |
""" |
|
|
97 |
Unregisters the given model(s). |
|
|
98 |
|
|
|
99 |
If a model isn't already registered, this will raise NotRegistered. |
|
|
100 |
""" |
|
|
101 |
if isinstance(model_or_iterable, ModelBase): |
|
|
102 |
model_or_iterable = [model_or_iterable] |
|
|
103 |
for model in model_or_iterable: |
|
|
104 |
if model not in self._registry: |
|
|
105 |
raise NotRegistered('The model %s is not registered' % model.__name__) |
|
|
106 |
del self._registry[model] |
|
|
107 |
|
|
|
108 |
def add_action(self, action, name=None): |
|
|
109 |
""" |
|
|
110 |
Register an action to be available globally. |
|
|
111 |
""" |
|
|
112 |
name = name or action.__name__ |
|
|
113 |
self._actions[name] = action |
|
|
114 |
self._global_actions[name] = action |
|
|
115 |
|
|
|
116 |
def disable_action(self, name): |
|
|
117 |
""" |
|
|
118 |
Disable a globally-registered action. Raises KeyError for invalid names. |
|
|
119 |
""" |
|
|
120 |
del self._actions[name] |
|
|
121 |
|
|
|
122 |
def get_action(self, name): |
|
|
123 |
""" |
|
|
124 |
Explicitally get a registered global action wheather it's enabled or |
|
|
125 |
not. Raises KeyError for invalid names. |
|
|
126 |
""" |
|
|
127 |
return self._global_actions[name] |
|
|
128 |
|
|
|
129 |
def actions(self): |
|
|
130 |
""" |
|
|
131 |
Get all the enabled actions as an iterable of (name, func). |
|
|
132 |
""" |
|
|
133 |
return self._actions.iteritems() |
|
|
134 |
actions = property(actions) |
|
|
135 |
|
|
|
136 |
def has_permission(self, request): |
|
|
137 |
""" |
|
|
138 |
Returns True if the given HttpRequest has permission to view |
|
|
139 |
*at least one* page in the admin site. |
|
|
140 |
""" |
|
|
141 |
return request.user.is_authenticated() and request.user.is_staff |
|
|
142 |
|
|
|
143 |
def check_dependencies(self): |
|
|
144 |
""" |
|
|
145 |
Check that all things needed to run the admin have been correctly installed. |
|
|
146 |
|
|
|
147 |
The default implementation checks that LogEntry, ContentType and the |
|
|
148 |
auth context processor are installed. |
|
|
149 |
""" |
|
|
150 |
from django.contrib.admin.models import LogEntry |
|
|
151 |
from django.contrib.contenttypes.models import ContentType |
|
|
152 |
|
|
|
153 |
if not LogEntry._meta.installed: |
|
|
154 |
raise ImproperlyConfigured("Put 'django.contrib.admin' in your INSTALLED_APPS setting in order to use the admin application.") |
|
|
155 |
if not ContentType._meta.installed: |
|
|
156 |
raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in your INSTALLED_APPS setting in order to use the admin application.") |
|
|
157 |
if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS: |
|
|
158 |
raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.") |
|
|
159 |
|
|
|
160 |
def admin_view(self, view, cacheable=False): |
|
|
161 |
""" |
|
|
162 |
Decorator to create an admin view attached to this ``AdminSite``. This |
|
|
163 |
wraps the view and provides permission checking by calling |
|
|
164 |
``self.has_permission``. |
|
|
165 |
|
|
|
166 |
You'll want to use this from within ``AdminSite.get_urls()``: |
|
|
167 |
|
|
|
168 |
class MyAdminSite(AdminSite): |
|
|
169 |
|
|
|
170 |
def get_urls(self): |
|
|
171 |
from django.conf.urls.defaults import patterns, url |
|
|
172 |
|
|
|
173 |
urls = super(MyAdminSite, self).get_urls() |
|
|
174 |
urls += patterns('', |
|
|
175 |
url(r'^my_view/$', self.admin_view(some_view)) |
|
|
176 |
) |
|
|
177 |
return urls |
|
|
178 |
|
|
|
179 |
By default, admin_views are marked non-cacheable using the |
|
|
180 |
``never_cache`` decorator. If the view can be safely cached, set |
|
|
181 |
cacheable=True. |
|
|
182 |
""" |
|
|
183 |
def inner(request, *args, **kwargs): |
|
|
184 |
if not self.has_permission(request): |
|
|
185 |
return self.login(request) |
|
|
186 |
return view(request, *args, **kwargs) |
|
|
187 |
if not cacheable: |
|
|
188 |
inner = never_cache(inner) |
|
|
189 |
return update_wrapper(inner, view) |
|
|
190 |
|
|
|
191 |
def get_urls(self): |
|
|
192 |
from django.conf.urls.defaults import patterns, url, include |
|
|
193 |
|
|
|
194 |
def wrap(view, cacheable=False): |
|
|
195 |
def wrapper(*args, **kwargs): |
|
|
196 |
return self.admin_view(view, cacheable)(*args, **kwargs) |
|
|
197 |
return update_wrapper(wrapper, view) |
|
|
198 |
|
|
|
199 |
# Admin-site-wide views. |
|
|
200 |
urlpatterns = patterns('', |
|
|
201 |
url(r'^$', |
|
|
202 |
wrap(self.index), |
|
|
203 |
name='index'), |
|
|
204 |
url(r'^logout/$', |
|
|
205 |
wrap(self.logout), |
|
|
206 |
name='logout'), |
|
|
207 |
url(r'^password_change/$', |
|
|
208 |
wrap(self.password_change, cacheable=True), |
|
|
209 |
name='password_change'), |
|
|
210 |
url(r'^password_change/done/$', |
|
|
211 |
wrap(self.password_change_done, cacheable=True), |
|
|
212 |
name='password_change_done'), |
|
|
213 |
url(r'^jsi18n/$', |
|
|
214 |
wrap(self.i18n_javascript, cacheable=True), |
|
|
215 |
name='jsi18n'), |
|
|
216 |
url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$', |
|
|
217 |
'django.views.defaults.shortcut'), |
|
|
218 |
url(r'^(?P<app_label>\w+)/$', |
|
|
219 |
wrap(self.app_index), |
|
|
220 |
name='app_list') |
|
|
221 |
) |
|
|
222 |
|
|
|
223 |
# Add in each model's views. |
|
|
224 |
for model, model_admin in self._registry.iteritems(): |
|
|
225 |
urlpatterns += patterns('', |
|
|
226 |
url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name), |
|
|
227 |
include(model_admin.urls)) |
|
|
228 |
) |
|
|
229 |
return urlpatterns |
|
|
230 |
|
|
|
231 |
def urls(self): |
|
|
232 |
return self.get_urls(), self.app_name, self.name |
|
|
233 |
urls = property(urls) |
|
|
234 |
|
|
|
235 |
def password_change(self, request): |
|
|
236 |
""" |
|
|
237 |
Handles the "change password" task -- both form display and validation. |
|
|
238 |
""" |
|
|
239 |
from django.contrib.auth.views import password_change |
|
|
240 |
if self.root_path is not None: |
|
|
241 |
url = '%spassword_change/done/' % self.root_path |
|
|
242 |
else: |
|
|
243 |
url = reverse('admin:password_change_done', current_app=self.name) |
|
|
244 |
return password_change(request, post_change_redirect=url) |
|
|
245 |
|
|
|
246 |
def password_change_done(self, request): |
|
|
247 |
""" |
|
|
248 |
Displays the "success" page after a password change. |
|
|
249 |
""" |
|
|
250 |
from django.contrib.auth.views import password_change_done |
|
|
251 |
return password_change_done(request) |
|
|
252 |
|
|
|
253 |
def i18n_javascript(self, request): |
|
|
254 |
""" |
|
|
255 |
Displays the i18n JavaScript that the Django admin requires. |
|
|
256 |
|
|
|
257 |
This takes into account the USE_I18N setting. If it's set to False, the |
|
|
258 |
generated JavaScript will be leaner and faster. |
|
|
259 |
""" |
|
|
260 |
if settings.USE_I18N: |
|
|
261 |
from django.views.i18n import javascript_catalog |
|
|
262 |
else: |
|
|
263 |
from django.views.i18n import null_javascript_catalog as javascript_catalog |
|
|
264 |
return javascript_catalog(request, packages='django.conf') |
|
|
265 |
|
|
|
266 |
def logout(self, request): |
|
|
267 |
""" |
|
|
268 |
Logs out the user for the given HttpRequest. |
|
|
269 |
|
|
|
270 |
This should *not* assume the user is already logged in. |
|
|
271 |
""" |
|
|
272 |
from django.contrib.auth.views import logout |
|
|
273 |
return logout(request) |
|
|
274 |
logout = never_cache(logout) |
|
|
275 |
|
|
|
276 |
def login(self, request): |
|
|
277 |
""" |
|
|
278 |
Displays the login form for the given HttpRequest. |
|
|
279 |
""" |
|
|
280 |
from django.contrib.auth.models import User |
|
|
281 |
|
|
|
282 |
# If this isn't already the login page, display it. |
|
|
283 |
if not request.POST.has_key(LOGIN_FORM_KEY): |
|
|
284 |
if request.POST: |
|
|
285 |
message = _("Please log in again, because your session has expired.") |
|
|
286 |
else: |
|
|
287 |
message = "" |
|
|
288 |
return self.display_login_form(request, message) |
|
|
289 |
|
|
|
290 |
# Check that the user accepts cookies. |
|
|
291 |
if not request.session.test_cookie_worked(): |
|
|
292 |
message = _("Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again.") |
|
|
293 |
return self.display_login_form(request, message) |
|
|
294 |
else: |
|
|
295 |
request.session.delete_test_cookie() |
|
|
296 |
|
|
|
297 |
# Check the password. |
|
|
298 |
username = request.POST.get('username', None) |
|
|
299 |
password = request.POST.get('password', None) |
|
|
300 |
user = authenticate(username=username, password=password) |
|
|
301 |
if user is None: |
|
|
302 |
message = ERROR_MESSAGE |
|
|
303 |
if username is not None and u'@' in username: |
|
|
304 |
# Mistakenly entered e-mail address instead of username? Look it up. |
|
|
305 |
try: |
|
|
306 |
user = User.objects.get(email=username) |
|
|
307 |
except (User.DoesNotExist, User.MultipleObjectsReturned): |
|
|
308 |
message = _("Usernames cannot contain the '@' character.") |
|
|
309 |
else: |
|
|
310 |
if user.check_password(password): |
|
|
311 |
message = _("Your e-mail address is not your username." |
|
|
312 |
" Try '%s' instead.") % user.username |
|
|
313 |
else: |
|
|
314 |
message = _("Usernames cannot contain the '@' character.") |
|
|
315 |
return self.display_login_form(request, message) |
|
|
316 |
|
|
|
317 |
# The user data is correct; log in the user in and continue. |
|
|
318 |
else: |
|
|
319 |
if user.is_active and user.is_staff: |
|
|
320 |
login(request, user) |
|
|
321 |
return http.HttpResponseRedirect(request.get_full_path()) |
|
|
322 |
else: |
|
|
323 |
return self.display_login_form(request, ERROR_MESSAGE) |
|
|
324 |
login = never_cache(login) |
|
|
325 |
|
|
|
326 |
def index(self, request, extra_context=None): |
|
|
327 |
""" |
|
|
328 |
Displays the main admin index page, which lists all of the installed |
|
|
329 |
apps that have been registered in this site. |
|
|
330 |
""" |
|
|
331 |
app_dict = {} |
|
|
332 |
user = request.user |
|
|
333 |
for model, model_admin in self._registry.items(): |
|
|
334 |
app_label = model._meta.app_label |
|
|
335 |
has_module_perms = user.has_module_perms(app_label) |
|
|
336 |
|
|
|
337 |
if has_module_perms: |
|
|
338 |
perms = model_admin.get_model_perms(request) |
|
|
339 |
|
|
|
340 |
# Check whether user has any perm for this module. |
|
|
341 |
# If so, add the module to the model_list. |
|
|
342 |
if True in perms.values(): |
|
|
343 |
model_dict = { |
|
|
344 |
'name': capfirst(model._meta.verbose_name_plural), |
|
|
345 |
'admin_url': mark_safe('%s/%s/' % (app_label, model.__name__.lower())), |
|
|
346 |
'perms': perms, |
|
|
347 |
} |
|
|
348 |
if app_label in app_dict: |
|
|
349 |
app_dict[app_label]['models'].append(model_dict) |
|
|
350 |
else: |
|
|
351 |
app_dict[app_label] = { |
|
|
352 |
'name': app_label.title(), |
|
|
353 |
'app_url': app_label + '/', |
|
|
354 |
'has_module_perms': has_module_perms, |
|
|
355 |
'models': [model_dict], |
|
|
356 |
} |
|
|
357 |
|
|
|
358 |
# Sort the apps alphabetically. |
|
|
359 |
app_list = app_dict.values() |
|
|
360 |
app_list.sort(lambda x, y: cmp(x['name'], y['name'])) |
|
|
361 |
|
|
|
362 |
# Sort the models alphabetically within each app. |
|
|
363 |
for app in app_list: |
|
|
364 |
app['models'].sort(lambda x, y: cmp(x['name'], y['name'])) |
|
|
365 |
|
|
|
366 |
context = { |
|
|
367 |
'title': _('Site administration'), |
|
|
368 |
'app_list': app_list, |
|
|
369 |
'root_path': self.root_path, |
|
|
370 |
} |
|
|
371 |
context.update(extra_context or {}) |
|
|
372 |
context_instance = template.RequestContext(request, current_app=self.name) |
|
|
373 |
return render_to_response(self.index_template or 'admin/index.html', context, |
|
|
374 |
context_instance=context_instance |
|
|
375 |
) |
|
|
376 |
index = never_cache(index) |
|
|
377 |
|
|
|
378 |
def display_login_form(self, request, error_message='', extra_context=None): |
|
|
379 |
request.session.set_test_cookie() |
|
|
380 |
context = { |
|
|
381 |
'title': _('Log in'), |
|
|
382 |
'app_path': request.get_full_path(), |
|
|
383 |
'error_message': error_message, |
|
|
384 |
'root_path': self.root_path, |
|
|
385 |
} |
|
|
386 |
context.update(extra_context or {}) |
|
|
387 |
context_instance = template.RequestContext(request, current_app=self.name) |
|
|
388 |
return render_to_response(self.login_template or 'admin/login.html', context, |
|
|
389 |
context_instance=context_instance |
|
|
390 |
) |
|
|
391 |
|
|
|
392 |
def app_index(self, request, app_label, extra_context=None): |
|
|
393 |
user = request.user |
|
|
394 |
has_module_perms = user.has_module_perms(app_label) |
|
|
395 |
app_dict = {} |
|
|
396 |
for model, model_admin in self._registry.items(): |
|
|
397 |
if app_label == model._meta.app_label: |
|
|
398 |
if has_module_perms: |
|
|
399 |
perms = model_admin.get_model_perms(request) |
|
|
400 |
|
|
|
401 |
# Check whether user has any perm for this module. |
|
|
402 |
# If so, add the module to the model_list. |
|
|
403 |
if True in perms.values(): |
|
|
404 |
model_dict = { |
|
|
405 |
'name': capfirst(model._meta.verbose_name_plural), |
|
|
406 |
'admin_url': '%s/' % model.__name__.lower(), |
|
|
407 |
'perms': perms, |
|
|
408 |
} |
|
|
409 |
if app_dict: |
|
|
410 |
app_dict['models'].append(model_dict), |
|
|
411 |
else: |
|
|
412 |
# First time around, now that we know there's |
|
|
413 |
# something to display, add in the necessary meta |
|
|
414 |
# information. |
|
|
415 |
app_dict = { |
|
|
416 |
'name': app_label.title(), |
|
|
417 |
'app_url': '', |
|
|
418 |
'has_module_perms': has_module_perms, |
|
|
419 |
'models': [model_dict], |
|
|
420 |
} |
|
|
421 |
if not app_dict: |
|
|
422 |
raise http.Http404('The requested admin page does not exist.') |
|
|
423 |
# Sort the models alphabetically within each app. |
|
|
424 |
app_dict['models'].sort(lambda x, y: cmp(x['name'], y['name'])) |
|
|
425 |
context = { |
|
|
426 |
'title': _('%s administration') % capfirst(app_label), |
|
|
427 |
'app_list': [app_dict], |
|
|
428 |
'root_path': self.root_path, |
|
|
429 |
} |
|
|
430 |
context.update(extra_context or {}) |
|
|
431 |
context_instance = template.RequestContext(request, current_app=self.name) |
|
|
432 |
return render_to_response(self.app_index_template or ('admin/%s/app_index.html' % app_label, |
|
|
433 |
'admin/app_index.html'), context, |
|
|
434 |
context_instance=context_instance |
|
|
435 |
) |
|
|
436 |
|
|
|
437 |
def root(self, request, url): |
|
|
438 |
""" |
|
|
439 |
DEPRECATED. This function is the old way of handling URL resolution, and |
|
|
440 |
is deprecated in favor of real URL resolution -- see ``get_urls()``. |
|
|
441 |
|
|
|
442 |
This function still exists for backwards-compatibility; it will be |
|
|
443 |
removed in Django 1.3. |
|
|
444 |
""" |
|
|
445 |
import warnings |
|
|
446 |
warnings.warn( |
|
|
447 |
"AdminSite.root() is deprecated; use include(admin.site.urls) instead.", |
|
|
448 |
PendingDeprecationWarning |
|
|
449 |
) |
|
|
450 |
|
|
|
451 |
# |
|
|
452 |
# Again, remember that the following only exists for |
|
|
453 |
# backwards-compatibility. Any new URLs, changes to existing URLs, or |
|
|
454 |
# whatever need to be done up in get_urls(), above! |
|
|
455 |
# |
|
|
456 |
|
|
|
457 |
if request.method == 'GET' and not request.path.endswith('/'): |
|
|
458 |
return http.HttpResponseRedirect(request.path + '/') |
|
|
459 |
|
|
|
460 |
if settings.DEBUG: |
|
|
461 |
self.check_dependencies() |
|
|
462 |
|
|
|
463 |
# Figure out the admin base URL path and stash it for later use |
|
|
464 |
self.root_path = re.sub(re.escape(url) + '$', '', request.path) |
|
|
465 |
|
|
|
466 |
url = url.rstrip('/') # Trim trailing slash, if it exists. |
|
|
467 |
|
|
|
468 |
# The 'logout' view doesn't require that the person is logged in. |
|
|
469 |
if url == 'logout': |
|
|
470 |
return self.logout(request) |
|
|
471 |
|
|
|
472 |
# Check permission to continue or display login form. |
|
|
473 |
if not self.has_permission(request): |
|
|
474 |
return self.login(request) |
|
|
475 |
|
|
|
476 |
if url == '': |
|
|
477 |
return self.index(request) |
|
|
478 |
elif url == 'password_change': |
|
|
479 |
return self.password_change(request) |
|
|
480 |
elif url == 'password_change/done': |
|
|
481 |
return self.password_change_done(request) |
|
|
482 |
elif url == 'jsi18n': |
|
|
483 |
return self.i18n_javascript(request) |
|
|
484 |
# URLs starting with 'r/' are for the "View on site" links. |
|
|
485 |
elif url.startswith('r/'): |
|
|
486 |
from django.contrib.contenttypes.views import shortcut |
|
|
487 |
return shortcut(request, *url.split('/')[1:]) |
|
|
488 |
else: |
|
|
489 |
if '/' in url: |
|
|
490 |
return self.model_page(request, *url.split('/', 2)) |
|
|
491 |
else: |
|
|
492 |
return self.app_index(request, url) |
|
|
493 |
|
|
|
494 |
raise http.Http404('The requested admin page does not exist.') |
|
|
495 |
|
|
|
496 |
def model_page(self, request, app_label, model_name, rest_of_url=None): |
|
|
497 |
""" |
|
|
498 |
DEPRECATED. This is the old way of handling a model view on the admin |
|
|
499 |
site; the new views should use get_urls(), above. |
|
|
500 |
""" |
|
|
501 |
from django.db import models |
|
|
502 |
model = models.get_model(app_label, model_name) |
|
|
503 |
if model is None: |
|
|
504 |
raise http.Http404("App %r, model %r, not found." % (app_label, model_name)) |
|
|
505 |
try: |
|
|
506 |
admin_obj = self._registry[model] |
|
|
507 |
except KeyError: |
|
|
508 |
raise http.Http404("This model exists but has not been registered with the admin site.") |
|
|
509 |
return admin_obj(request, rest_of_url) |
|
|
510 |
model_page = never_cache(model_page) |
|
|
511 |
|
|
|
512 |
# This global object represents the default admin site, for the common case. |
|
|
513 |
# You can instantiate AdminSite in your own code to create a custom admin site. |
|
|
514 |
site = AdminSite() |