1 import re |
1 import re |
2 from django import http, template |
2 from django import http, template |
3 from django.contrib.admin import ModelAdmin |
3 from django.contrib.admin import ModelAdmin |
4 from django.contrib.admin import actions |
4 from django.contrib.admin import actions |
5 from django.contrib.auth import authenticate, login |
5 from django.contrib.auth import authenticate, login |
|
6 from django.views.decorators.csrf import csrf_protect |
6 from django.db.models.base import ModelBase |
7 from django.db.models.base import ModelBase |
7 from django.core.exceptions import ImproperlyConfigured |
8 from django.core.exceptions import ImproperlyConfigured |
8 from django.core.urlresolvers import reverse |
9 from django.core.urlresolvers import reverse |
9 from django.shortcuts import render_to_response |
10 from django.shortcuts import render_to_response |
10 from django.utils.functional import update_wrapper |
11 from django.utils.functional import update_wrapper |
11 from django.utils.safestring import mark_safe |
12 from django.utils.safestring import mark_safe |
12 from django.utils.text import capfirst |
13 from django.utils.text import capfirst |
13 from django.utils.translation import ugettext_lazy, ugettext as _ |
14 from django.utils.translation import ugettext_lazy, ugettext as _ |
14 from django.views.decorators.cache import never_cache |
15 from django.views.decorators.cache import never_cache |
15 from django.conf import settings |
16 from django.conf import settings |
16 try: |
|
17 set |
|
18 except NameError: |
|
19 from sets import Set as set # Python 2.3 fallback |
|
20 |
17 |
21 ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") |
18 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' |
19 LOGIN_FORM_KEY = 'this_is_the_login_form' |
23 |
20 |
24 class AlreadyRegistered(Exception): |
21 class AlreadyRegistered(Exception): |
34 register() method, and the root() method can then be used as a Django view function |
31 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. |
32 that presents a full admin interface for the collection of registered models. |
36 """ |
33 """ |
37 |
34 |
38 index_template = None |
35 index_template = None |
|
36 app_index_template = None |
39 login_template = None |
37 login_template = None |
40 app_index_template = None |
38 logout_template = None |
|
39 password_change_template = None |
|
40 password_change_done_template = None |
41 |
41 |
42 def __init__(self, name=None, app_name='admin'): |
42 def __init__(self, name=None, app_name='admin'): |
43 self._registry = {} # model_class class -> admin_class instance |
43 self._registry = {} # model_class class -> admin_class instance |
44 self.root_path = None |
44 self.root_path = None |
45 if name is None: |
45 if name is None: |
136 def has_permission(self, request): |
136 def has_permission(self, request): |
137 """ |
137 """ |
138 Returns True if the given HttpRequest has permission to view |
138 Returns True if the given HttpRequest has permission to view |
139 *at least one* page in the admin site. |
139 *at least one* page in the admin site. |
140 """ |
140 """ |
141 return request.user.is_authenticated() and request.user.is_staff |
141 return request.user.is_active and request.user.is_staff |
142 |
142 |
143 def check_dependencies(self): |
143 def check_dependencies(self): |
144 """ |
144 """ |
145 Check that all things needed to run the admin have been correctly installed. |
145 Check that all things needed to run the admin have been correctly installed. |
146 |
146 |
149 """ |
149 """ |
150 from django.contrib.admin.models import LogEntry |
150 from django.contrib.admin.models import LogEntry |
151 from django.contrib.contenttypes.models import ContentType |
151 from django.contrib.contenttypes.models import ContentType |
152 |
152 |
153 if not LogEntry._meta.installed: |
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.") |
154 raise ImproperlyConfigured("Put 'django.contrib.admin' in your " |
|
155 "INSTALLED_APPS setting in order to use the admin application.") |
155 if not ContentType._meta.installed: |
156 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 raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in " |
157 if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS: |
158 "your INSTALLED_APPS setting in order to use the admin application.") |
158 raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.") |
159 if not ('django.contrib.auth.context_processors.auth' in settings.TEMPLATE_CONTEXT_PROCESSORS or |
|
160 'django.core.context_processors.auth' in settings.TEMPLATE_CONTEXT_PROCESSORS): |
|
161 raise ImproperlyConfigured("Put 'django.contrib.auth.context_processors.auth' " |
|
162 "in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.") |
159 |
163 |
160 def admin_view(self, view, cacheable=False): |
164 def admin_view(self, view, cacheable=False): |
161 """ |
165 """ |
162 Decorator to create an admin view attached to this ``AdminSite``. This |
166 Decorator to create an admin view attached to this ``AdminSite``. This |
163 wraps the view and provides permission checking by calling |
167 wraps the view and provides permission checking by calling |
184 if not self.has_permission(request): |
188 if not self.has_permission(request): |
185 return self.login(request) |
189 return self.login(request) |
186 return view(request, *args, **kwargs) |
190 return view(request, *args, **kwargs) |
187 if not cacheable: |
191 if not cacheable: |
188 inner = never_cache(inner) |
192 inner = never_cache(inner) |
|
193 # We add csrf_protect here so this function can be used as a utility |
|
194 # function for any view, without having to repeat 'csrf_protect'. |
|
195 if not getattr(view, 'csrf_exempt', False): |
|
196 inner = csrf_protect(inner) |
189 return update_wrapper(inner, view) |
197 return update_wrapper(inner, view) |
190 |
198 |
191 def get_urls(self): |
199 def get_urls(self): |
192 from django.conf.urls.defaults import patterns, url, include |
200 from django.conf.urls.defaults import patterns, url, include |
|
201 |
|
202 if settings.DEBUG: |
|
203 self.check_dependencies() |
193 |
204 |
194 def wrap(view, cacheable=False): |
205 def wrap(view, cacheable=False): |
195 def wrapper(*args, **kwargs): |
206 def wrapper(*args, **kwargs): |
196 return self.admin_view(view, cacheable)(*args, **kwargs) |
207 return self.admin_view(view, cacheable)(*args, **kwargs) |
197 return update_wrapper(wrapper, view) |
208 return update_wrapper(wrapper, view) |
239 from django.contrib.auth.views import password_change |
250 from django.contrib.auth.views import password_change |
240 if self.root_path is not None: |
251 if self.root_path is not None: |
241 url = '%spassword_change/done/' % self.root_path |
252 url = '%spassword_change/done/' % self.root_path |
242 else: |
253 else: |
243 url = reverse('admin:password_change_done', current_app=self.name) |
254 url = reverse('admin:password_change_done', current_app=self.name) |
244 return password_change(request, post_change_redirect=url) |
255 defaults = { |
|
256 'post_change_redirect': url |
|
257 } |
|
258 if self.password_change_template is not None: |
|
259 defaults['template_name'] = self.password_change_template |
|
260 return password_change(request, **defaults) |
245 |
261 |
246 def password_change_done(self, request): |
262 def password_change_done(self, request): |
247 """ |
263 """ |
248 Displays the "success" page after a password change. |
264 Displays the "success" page after a password change. |
249 """ |
265 """ |
250 from django.contrib.auth.views import password_change_done |
266 from django.contrib.auth.views import password_change_done |
251 return password_change_done(request) |
267 defaults = {} |
|
268 if self.password_change_done_template is not None: |
|
269 defaults['template_name'] = self.password_change_done_template |
|
270 return password_change_done(request, **defaults) |
252 |
271 |
253 def i18n_javascript(self, request): |
272 def i18n_javascript(self, request): |
254 """ |
273 """ |
255 Displays the i18n JavaScript that the Django admin requires. |
274 Displays the i18n JavaScript that the Django admin requires. |
256 |
275 |
268 Logs out the user for the given HttpRequest. |
287 Logs out the user for the given HttpRequest. |
269 |
288 |
270 This should *not* assume the user is already logged in. |
289 This should *not* assume the user is already logged in. |
271 """ |
290 """ |
272 from django.contrib.auth.views import logout |
291 from django.contrib.auth.views import logout |
273 return logout(request) |
292 defaults = {} |
|
293 if self.logout_template is not None: |
|
294 defaults['template_name'] = self.logout_template |
|
295 return logout(request, **defaults) |
274 logout = never_cache(logout) |
296 logout = never_cache(logout) |
275 |
297 |
276 def login(self, request): |
298 def login(self, request): |
277 """ |
299 """ |
278 Displays the login form for the given HttpRequest. |
300 Displays the login form for the given HttpRequest. |
443 removed in Django 1.3. |
465 removed in Django 1.3. |
444 """ |
466 """ |
445 import warnings |
467 import warnings |
446 warnings.warn( |
468 warnings.warn( |
447 "AdminSite.root() is deprecated; use include(admin.site.urls) instead.", |
469 "AdminSite.root() is deprecated; use include(admin.site.urls) instead.", |
448 PendingDeprecationWarning |
470 DeprecationWarning |
449 ) |
471 ) |
450 |
472 |
451 # |
473 # |
452 # Again, remember that the following only exists for |
474 # Again, remember that the following only exists for |
453 # backwards-compatibility. Any new URLs, changes to existing URLs, or |
475 # backwards-compatibility. Any new URLs, changes to existing URLs, or |