Code

Ticket #10061: admin-urls.3.diff

File admin-urls.3.diff, 9.5 KB (added by Alex, 5 years ago)

added tests

Line 
1diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
2index ed41c7f..6f063f0 100644
3--- a/django/contrib/admin/options.py
4+++ b/django/contrib/admin/options.py
5@@ -437,6 +437,7 @@ class ModelAdmin(BaseModelAdmin):
6             'save_as': self.save_as,
7             'save_on_top': self.save_on_top,
8             'root_path': self.admin_site.root_path,
9+            'admin_site': self.admin_site.name,
10         })
11         return render_to_response(self.change_form_template or [
12             "admin/%s/%s/change_form.html" % (app_label, opts.object_name.lower()),
13@@ -571,6 +572,7 @@ class ModelAdmin(BaseModelAdmin):
14             'errors': helpers.AdminErrorList(form, formsets),
15             'root_path': self.admin_site.root_path,
16             'app_label': opts.app_label,
17+            'admin_site': self.admin_site.name,
18         }
19         context.update(extra_context or {})
20         return self.render_change_form(request, context, add=True)
21@@ -649,6 +651,7 @@ class ModelAdmin(BaseModelAdmin):
22             'inline_admin_formsets': inline_admin_formsets,
23             'errors': helpers.AdminErrorList(form, formsets),
24             'root_path': self.admin_site.root_path,
25+            'admin_site': self.admin_site.name,
26             'app_label': opts.app_label,
27         }
28         context.update(extra_context or {})
29@@ -681,6 +684,7 @@ class ModelAdmin(BaseModelAdmin):
30             'cl': cl,
31             'has_add_permission': self.has_add_permission(request),
32             'root_path': self.admin_site.root_path,
33+            'admin_site': self.admin_site.name,
34             'app_label': app_label,
35         }
36         context.update(extra_context or {})
37@@ -736,6 +740,7 @@ class ModelAdmin(BaseModelAdmin):
38             "perms_lacking": perms_needed,
39             "opts": opts,
40             "root_path": self.admin_site.root_path,
41+            'admin_site': self.admin_site.name,
42             "app_label": app_label,
43         }
44         context.update(extra_context or {})
45@@ -763,6 +768,7 @@ class ModelAdmin(BaseModelAdmin):
46             'module_name': capfirst(force_unicode(opts.verbose_name_plural)),
47             'object': obj,
48             'root_path': self.admin_site.root_path,
49+            'admin_site': self.admin_site.name,
50             'app_label': app_label,
51         }
52         context.update(extra_context or {})
53diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
54index 42ce296..d77eebd 100644
55--- a/django/contrib/admin/sites.py
56+++ b/django/contrib/admin/sites.py
57@@ -3,6 +3,7 @@ from django import http, template
58 from django.contrib.admin import ModelAdmin
59 from django.contrib.auth import authenticate, login
60 from django.db.models.base import ModelBase
61+from django.core.urlresolvers import reverse
62 from django.core.exceptions import ImproperlyConfigured
63 from django.shortcuts import render_to_response
64 from django.utils.functional import update_wrapper
65@@ -35,10 +36,7 @@ class AdminSite(object):
66     
67     def __init__(self, name=None):
68         self._registry = {} # model_class class -> admin_class instance
69-        # TODO Root path is used to calculate urls under the old root() method
70-        # in order to maintain backwards compatibility we are leaving that in
71-        # so root_path isn't needed, not sure what to do about this.
72-        self.root_path = 'admin/'
73+        self.root_path = None
74         if name is None:
75             name = ''
76         else:
77@@ -163,7 +161,7 @@ class AdminSite(object):
78                 name='%sadmin_index' % self.name),
79             url(r'^logout/$',
80                 wrap(self.logout),
81-                name='%sadmin_logout'),
82+                name='%sadmin_logout' % self.name),
83             url(r'^password_change/$',
84                 wrap(self.password_change),
85                 name='%sadmin_password_change' % self.name),
86@@ -197,8 +195,12 @@ class AdminSite(object):
87         Handles the "change password" task -- both form display and validation.
88         """
89         from django.contrib.auth.views import password_change
90+        if self.root_path is not None:
91+            url = '%spassword_change/done/' % self.root_path
92+        else:
93+            url = reverse('%sadmin_password_change_done' % self.name)
94         return password_change(request,
95-            post_change_redirect='%spassword_change/done/' % self.root_path)
96+            post_change_redirect=url)
97     
98     def password_change_done(self, request):
99         """
100@@ -328,6 +330,7 @@ class AdminSite(object):
101             'title': _('Site administration'),
102             'app_list': app_list,
103             'root_path': self.root_path,
104+            'admin_site': self.name
105         }
106         context.update(extra_context or {})
107         return render_to_response(self.index_template or 'admin/index.html', context,
108@@ -342,6 +345,7 @@ class AdminSite(object):
109             'app_path': request.get_full_path(),
110             'error_message': error_message,
111             'root_path': self.root_path,
112+            'admin_site': self.name,
113         }
114         context.update(extra_context or {})
115         return render_to_response(self.login_template or 'admin/login.html', context,
116@@ -388,6 +392,7 @@ class AdminSite(object):
117             'title': _('%s administration') % capfirst(app_label),
118             'app_list': [app_dict],
119             'root_path': self.root_path,
120+            'admin_site': self.name,
121         }
122         context.update(extra_context or {})
123         return render_to_response(self.app_index_template or 'admin/app_index.html', context,
124diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
125index e969d1b..623d769 100644
126--- a/django/contrib/admin/templates/admin/base.html
127+++ b/django/contrib/admin/templates/admin/base.html
128@@ -25,7 +25,36 @@
129         {% block branding %}{% endblock %}
130         </div>
131         {% if user.is_authenticated and user.is_staff %}
132-        <div id="user-tools">{% trans 'Welcome,' %} <strong>{% firstof user.first_name user.username %}</strong>. {% block userlinks %}{% url django-admindocs-docroot as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}<a href="{{ root_path }}password_change/">{% trans 'Change password' %}</a> / <a href="{{ root_path }}logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
133+        <div id="user-tools">
134+            {% trans 'Welcome,' %}
135+            <strong>
136+                {% firstof user.first_name user.username %}
137+            </strong>.
138+            {% block userlinks %}
139+                {% url django-admindocs-docroot as docsroot %}
140+                {% if docsroot %}
141+                    <a href="{{ docsroot }}">
142+                        {% trans 'Documentation' %}
143+                    </a> /
144+                {% endif %}
145+                {% url admin_site:admin_password_change as password_change_url %}
146+                {% if password_change_url %}
147+                    <a href="{{ password_change_url }}">
148+                {% else %}
149+                    <a href="{{ root_path }}password_change/">
150+                {% endif %}
151+                    {% trans 'Change password' %}
152+                </a> /
153+                {% url admin_site:admin_logout as logout_url %}
154+                {% if logout_url %}
155+                    <a href="{{ logout_url }}">
156+                {% else %}
157+                    <a href="{{ root_path }}logout/">
158+                {% endif %}
159+                    {% trans 'Log out' %}
160+                </a>
161+            {% endblock %}
162+        </div>
163         {% endif %}
164         {% block nav-global %}{% endblock %}
165     </div>
166diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
167index 0911309..cc3cdd1 100644
168--- a/django/template/defaulttags.py
169+++ b/django/template/defaulttags.py
170@@ -368,6 +368,10 @@ class URLNode(Node):
171 
172     def render(self, context):
173         from django.core.urlresolvers import reverse, NoReverseMatch
174+        if len(self.view_name) > 1:
175+            self.view_name = Variable(self.view_name[0]).resolve(context) + self.view_name[1]
176+        else:
177+            self.view_name = self.view_name[0]
178         args = [arg.resolve(context) for arg in self.args]
179         kwargs = dict([(smart_str(k,'ascii'), v.resolve(context))
180                        for k, v in self.kwargs.items()])
181@@ -1102,6 +1106,10 @@ def url(parser, token):
182         raise TemplateSyntaxError("'%s' takes at least one argument"
183                                   " (path to a view)" % bits[0])
184     viewname = bits[1]
185+    if ':' in viewname:
186+        viewname = viewname.split(':')
187+    else:
188+        viewname = [viewname]
189     args = []
190     kwargs = {}
191     asvar = None
192diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
193index 39daf11..7a4f09c 100644
194--- a/tests/regressiontests/admin_views/tests.py
195+++ b/tests/regressiontests/admin_views/tests.py
196@@ -172,6 +172,11 @@ class AdminViewBasicTest(TestCase):
197         self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)       
198         response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'})
199         self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
200+   
201+    def testLogoutAndPasswordChangeURLs(self):
202+        response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit)
203+        self.failIf('%s/logout/">' % self.urlbit not in response.content)
204+        self.failIf('%s/password_change/">' % self.urlbit not in response.content)
205 
206 class CustomModelAdminTest(AdminViewBasicTest):
207     urlbit = "admin2"