Code

Ticket #6470: admin-urlpatterns.2.diff

File admin-urlpatterns.2.diff, 15.9 KB (added by Alex, 5 years ago)

small update to always use raw strings

Line 
1diff --git a/django/conf/project_template/urls.py b/django/conf/project_template/urls.py
2index af1d1db..dfb49d3 100644
3--- a/django/conf/project_template/urls.py
4+++ b/django/conf/project_template/urls.py
5@@ -13,5 +13,5 @@ urlpatterns = patterns('',
6     # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
7 
8     # Uncomment the next line to enable the admin:
9-    # (r'^admin/(.*)', admin.site.root),
10+    # (r'^admin/', include(admin.site.urls)),
11 )
12diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
13index 3d60b9d..966e96c 100644
14--- a/django/contrib/admin/options.py
15+++ b/django/contrib/admin/options.py
16@@ -1,3 +1,5 @@
17+import types
18+
19 from django import forms, template
20 from django.forms.formsets import all_valid
21 from django.forms.models import modelform_factory, inlineformset_factory
22@@ -5,7 +7,7 @@ from django.forms.models import BaseInlineFormSet
23 from django.contrib.contenttypes.models import ContentType
24 from django.contrib.admin import widgets
25 from django.contrib.admin import helpers
26-from django.contrib.admin.util import quote, unquote, flatten_fieldsets, get_deleted_objects
27+from django.contrib.admin.util import quote, unquote, flatten_fieldsets, get_deleted_objects, admin_perm_test
28 from django.core.exceptions import PermissionDenied
29 from django.db import models, transaction
30 from django.http import Http404, HttpResponse, HttpResponseRedirect
31@@ -196,6 +198,22 @@ class ModelAdmin(BaseModelAdmin):
32         else:
33             return self.change_view(request, unquote(url))
34 
35+    def _get_urls(self):
36+        from django.conf.urls.defaults import patterns, url
37+        urls_module = types.ModuleType('%s.urls' % self.__class__.__name__)
38+        info = self.admin_site.name, self.model._meta.app_label, self.model._meta.module_name
39+        urlpatterns = patterns('',
40+            url(r'^$', lambda *args, **kwargs: self.changelist_view(*args, **kwargs), name='%sadmin_%s_%s_changelist' % info),
41+            url(r'^add/$', lambda *args, **kwargs: self.add_view(*args, **kwargs), name='%sadmin_%s_%s_add' % info),
42+            url(r'^(.+)/history/$', lambda *args, **kwargs: self.history_view(*args, **kwargs), name='%sadmin_%s_%s_history' % info),
43+            url(r'^(.+)/delete/$', lambda *args, **kwargs: self.delete_view(*args, **kwargs), name='%sadmin_%s_%s_delete' % info),
44+            url(r'^(.+)/$', lambda *args, **kwargs: self.change_view(*args, **kwargs), name='%sadmin_%s_%s_change' % info),
45+        )
46+        urls_module.urlpatterns = urlpatterns
47+        return urls_module
48+    urls = property(_get_urls)
49+
50+
51     def _media(self):
52         from django.conf import settings
53 
54@@ -537,7 +555,7 @@ class ModelAdmin(BaseModelAdmin):
55         }
56         context.update(extra_context or {})
57         return self.render_change_form(request, context, add=True)
58-    add_view = transaction.commit_on_success(add_view)
59+    add_view = transaction.commit_on_success(admin_perm_test(add_view))
60 
61     def change_view(self, request, object_id, extra_context=None):
62         "The 'change' admin view for this model."
63@@ -545,7 +563,7 @@ class ModelAdmin(BaseModelAdmin):
64         opts = model._meta
65 
66         try:
67-            obj = model._default_manager.get(pk=object_id)
68+            obj = model._default_manager.get(pk=unquote(object_id))
69         except model.DoesNotExist:
70             # Don't raise Http404 just yet, because we haven't checked
71             # permissions yet. We don't want an unauthenticated user to be able
72@@ -616,7 +634,7 @@ class ModelAdmin(BaseModelAdmin):
73         }
74         context.update(extra_context or {})
75         return self.render_change_form(request, context, change=True, obj=obj)
76-    change_view = transaction.commit_on_success(change_view)
77+    change_view = transaction.commit_on_success(admin_perm_test(change_view))
78 
79     def changelist_view(self, request, extra_context=None):
80         "The 'change list' admin view for this model."
81@@ -652,6 +670,7 @@ class ModelAdmin(BaseModelAdmin):
82             'admin/%s/change_list.html' % app_label,
83             'admin/change_list.html'
84         ], context, context_instance=template.RequestContext(request))
85+    changelist_view = admin_perm_test(changelist_view)
86 
87     def delete_view(self, request, object_id, extra_context=None):
88         "The 'delete' admin view for this model."
89@@ -659,7 +678,7 @@ class ModelAdmin(BaseModelAdmin):
90         app_label = opts.app_label
91 
92         try:
93-            obj = self.model._default_manager.get(pk=object_id)
94+            obj = self.model._default_manager.get(pk=unquote(object_id))
95         except self.model.DoesNotExist:
96             # Don't raise Http404 just yet, because we haven't checked
97             # permissions yet. We don't want an unauthenticated user to be able
98@@ -674,7 +693,7 @@ class ModelAdmin(BaseModelAdmin):
99 
100         # Populate deleted_objects, a data structure of all related objects that
101         # will also be deleted.
102-        deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), quote(object_id), escape(obj))), []]
103+        deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), object_id, escape(obj))), []]
104         perms_needed = set()
105         get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
106 
107@@ -707,6 +726,7 @@ class ModelAdmin(BaseModelAdmin):
108             "admin/%s/delete_confirmation.html" % app_label,
109             "admin/delete_confirmation.html"
110         ], context, context_instance=template.RequestContext(request))
111+    delete_view = admin_perm_test(delete_view)
112 
113     def history_view(self, request, object_id, extra_context=None):
114         "The 'history' admin view for this model."
115@@ -734,6 +754,7 @@ class ModelAdmin(BaseModelAdmin):
116             "admin/%s/object_history.html" % app_label,
117             "admin/object_history.html"
118         ], context, context_instance=template.RequestContext(request))
119+    history_view = admin_perm_test(history_view)
120 
121 class InlineModelAdmin(BaseModelAdmin):
122     """
123diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
124index c16ab6a..86c063f 100644
125--- a/django/contrib/admin/sites.py
126+++ b/django/contrib/admin/sites.py
127@@ -1,7 +1,10 @@
128 import base64
129 import re
130+import types
131+
132 from django import http, template
133 from django.contrib.admin import ModelAdmin
134+from django.contrib.admin.util import admin_perm_test
135 from django.contrib.auth import authenticate, login
136 from django.db.models.base import ModelBase
137 from django.core.exceptions import ImproperlyConfigured
138@@ -34,8 +37,17 @@ class AdminSite(object):
139     login_template = None
140     app_index_template = None
141 
142-    def __init__(self):
143+    def __init__(self, name=None):
144         self._registry = {} # model_class class -> admin_class instance
145+        # TODO Root path is used to calculate urls under the old root() method
146+        # in order to maintain backwards compatibility we are leaving that in
147+        # so root_path isn't needed, not sure what to do about this.
148+        self.root_path = 'admin/'
149+        if name is None:
150+            name = ''
151+        else:
152+            name += '_'
153+        self.name = name
154 
155     def register(self, model_or_iterable, admin_class=None, **options):
156         """
157@@ -121,6 +133,9 @@ class AdminSite(object):
158 
159         `url` is the remainder of the URL -- e.g. 'comments/comment/'.
160         """
161+        import warnings
162+        warnings.warn("Using AdminSite.root() is deprecated, you should \
163+            include(AdminSite.urls) instead", PendingDeprecationWarning)
164         if request.method == 'GET' and not request.path.endswith('/'):
165             return http.HttpResponseRedirect(request.path + '/')
166 
167@@ -159,7 +174,28 @@ class AdminSite(object):
168                 return self.app_index(request, url)
169 
170         raise http.Http404('The requested admin page does not exist.')
171-
172+   
173+    def _get_urls(self):
174+        from django.conf.urls.defaults import patterns, url, include
175+        from django.core.urlresolvers import RegexURLResolver
176+        urls_module = types.ModuleType('%s.urls' % self.__class__.__name__)
177+        urlpatterns = patterns('',
178+            url(r'^$', lambda *args, **kwargs: self.index(*args, **kwargs), name='%sadmin_index' % self.name),
179+            url(r'^logout/$', lambda *args, **kwargs: self.logout(*args, **kwargs), name='%sadmin_logout'),
180+            url(r'^password_change/$', lambda *args, **kwargs: self.password_change(*args, **kwargs), name='%sadmin_password_change' % self.name),
181+            url(r'^password_change/done/$', lambda *args, **kwargs: self.password_change_done(*args, **kwargs), name='%sadmin_password_change_done' % self.name),
182+            url(r'^jsi18n/$', lambda *args, **kwargs: self.i18n_javascript(*args, **kwargs), name='%sadmin_jsi18n' % self.name),
183+            url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$', 'django.views.defaults.shortcut'),
184+            url(r'^(?P<app_label>\w+)/$', lambda *args, **kwargs: self.app_index(*args, **kwargs), name='%sadmin_app_list' % self.name),
185+        )
186+        for model, model_admin in self._registry.iteritems():
187+            urlpatterns += patterns('',
188+                url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name), include(model_admin.urls))
189+            )
190+        urls_module.urlpatterns = urlpatterns
191+        return urls_module
192+    urls = property(_get_urls)
193+   
194     def model_page(self, request, app_label, model_name, rest_of_url=None):
195         """
196         Handles the model-specific functionality of the admin site, delegating
197@@ -183,6 +219,7 @@ class AdminSite(object):
198         from django.contrib.auth.views import password_change
199         return password_change(request,
200             post_change_redirect='%spassword_change/done/' % self.root_path)
201+    passoword_change = admin_perm_test(password_change)
202 
203     def password_change_done(self, request):
204         """
205@@ -190,6 +227,7 @@ class AdminSite(object):
206         """
207         from django.contrib.auth.views import password_change_done
208         return password_change_done(request)
209+    password_change_done = admin_perm_test(password_change_done)
210 
211     def i18n_javascript(self, request):
212         """
213@@ -203,6 +241,7 @@ class AdminSite(object):
214         else:
215             from django.views.i18n import null_javascript_catalog as javascript_catalog
216         return javascript_catalog(request, packages='django.conf')
217+    i18n_javascript = admin_perm_test(i18n_javascript)
218 
219     def logout(self, request):
220         """
221@@ -317,7 +356,7 @@ class AdminSite(object):
222         return render_to_response(self.index_template or 'admin/index.html', context,
223             context_instance=template.RequestContext(request)
224         )
225-    index = never_cache(index)
226+    index = never_cache(admin_perm_test(index))
227 
228     def display_login_form(self, request, error_message='', extra_context=None):
229         request.session.set_test_cookie()
230@@ -377,6 +416,7 @@ class AdminSite(object):
231         return render_to_response(self.app_index_template or 'admin/app_index.html', context,
232             context_instance=template.RequestContext(request)
233         )
234+    app_index = admin_perm_test(app_index)
235 
236 # This global object represents the default admin site, for the common case.
237 # You can instantiate AdminSite in your own code to create a custom admin site.
238diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py
239index 0900b4e..6b34c78 100644
240--- a/django/contrib/admin/util.py
241+++ b/django/contrib/admin/util.py
242@@ -6,6 +6,17 @@ from django.utils.text import capfirst
243 from django.utils.encoding import force_unicode
244 from django.utils.translation import ugettext as _
245 
246+def admin_perm_test(func):
247+    def inner(admin_site_or_modeladmin, request, *args, **kwargs):
248+        if hasattr(admin_site_or_modeladmin, 'has_permission'):
249+            admin_site = admin_site_or_modeladmin
250+        else:
251+            admin_site = admin_site_or_modeladmin.admin_site
252+        if not admin_site.has_permission(request):
253+            return admin_site.login(request)
254+        # User has right permisssions show the view
255+        return func(admin_site_or_modeladmin, request, *args, **kwargs)
256+    return inner
257 
258 def quote(s):
259     """
260diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
261index 774e6d3..897cde2 100644
262--- a/django/core/urlresolvers.py
263+++ b/django/core/urlresolvers.py
264@@ -143,6 +143,8 @@ class RegexURLResolver(object):
265         # urlconf_name is a string representing the module containing urlconfs.
266         self.regex = re.compile(regex, re.UNICODE)
267         self.urlconf_name = urlconf_name
268+        if not isinstance(self.urlconf_name, basestring):
269+            self._urlconf_module = self.urlconf_name
270         self.callback = None
271         self.default_kwargs = default_kwargs or {}
272         self._reverse_dict = MultiValueDict()
273diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt
274index 1144167..fb6794b 100644
275--- a/docs/intro/tutorial02.txt
276+++ b/docs/intro/tutorial02.txt
277@@ -57,7 +57,7 @@ activate the admin site for your installation, do these three things:
278               # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
279 
280               # Uncomment the next line to enable the admin:
281-              **(r'^admin/(.*)', admin.site.root),**
282+              **(r'^admin/', include(admin.site.urls)),**
283           )
284 
285       (The bold lines are the ones that needed to be uncommented.)
286diff --git a/docs/ref/contrib/admin.txt b/docs/ref/contrib/admin.txt
287index f24dc46..f80754d 100644
288--- a/docs/ref/contrib/admin.txt
289+++ b/docs/ref/contrib/admin.txt
290@@ -1027,7 +1027,7 @@ In this example, we register the default ``AdminSite`` instance
291     admin.autodiscover()
292 
293     urlpatterns = patterns('',
294-        ('^admin/(.*)', admin.site.root),
295+        ('^admin/', include(admin.site.urls)),
296     )
297 
298 Above we used ``admin.autodiscover()`` to automatically load the
299@@ -1041,15 +1041,13 @@ In this example, we register the ``AdminSite`` instance
300     from myproject.admin import admin_site
301 
302     urlpatterns = patterns('',
303-        ('^myadmin/(.*)', admin_site.root),
304+        ('^myadmin/', include(admin_site.urls)),
305     )
306 
307 There is really no need to use autodiscover when using your own ``AdminSite``
308 instance since you will likely be importing all the per-app admin.py modules
309 in your ``myproject.admin`` module.
310 
311-Note that the regular expression in the URLpattern *must* group everything in
312-the URL that comes after the URL root -- hence the ``(.*)`` in these examples.
313 
314 Multiple admin sites in the same URLconf
315 ----------------------------------------
316@@ -1068,6 +1066,6 @@ respectively::
317     from myproject.admin import basic_site, advanced_site
318 
319     urlpatterns = patterns('',
320-        ('^basic-admin/(.*)', basic_site.root),
321-        ('^advanced-admin/(.*)', advanced_site.root),
322+        ('^basic-admin/', include(basic_site.root)),
323+        ('^advanced-admin/', include(advanced_site.root)),
324     )
325diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
326index 391d1ff..8fb8ad8 100644
327--- a/tests/regressiontests/admin_views/tests.py
328+++ b/tests/regressiontests/admin_views/tests.py
329@@ -26,7 +26,7 @@ class AdminViewBasicTest(TestCase):
330         """
331         request = self.client.get('/test_admin/admin/admin_views/article/add')
332         self.assertRedirects(request,
333-            '/test_admin/admin/admin_views/article/add/'
334+            '/test_admin/admin/admin_views/article/add/', status_code=301
335         )
336     
337     def testBasicAddGet(self):
338diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py
339index 4e5da48..02e0286 100644
340--- a/tests/regressiontests/admin_views/urls.py
341+++ b/tests/regressiontests/admin_views/urls.py
342@@ -5,5 +5,5 @@ import views
343 urlpatterns = patterns('',
344     (r'^admin/doc/', include('django.contrib.admindocs.urls')),
345     (r'^admin/secure-view/$', views.secure_view),
346-    (r'^admin/(.*)', admin.site.root),
347+    (r'^admin/', include(admin.site.urls)),
348 )