Permalink
Browse files

Fixed #10061 -- Added namespacing for named URLs - most importantly, …

…for the admin site, where the absence of this facility was causing problems. Thanks to the many people who contributed to and helped review this patch.

This change is backwards incompatible for anyone that is using the named URLs
introduced in [9739]. Any usage of the old admin_XXX names need to be modified
to use the new namespaced format; in many cases this will be as simple as a
search & replace for "admin_" -> "admin:". See the docs for more details on
the new URL names, and the namespace resolution strategy.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@11250 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 9fd19c0 commit 8d48eaa064c88533be5082e3f45638fbd48491d8 @freakboy3742 freakboy3742 committed Jul 16, 2009
@@ -6,7 +6,16 @@
handler404 = 'django.views.defaults.page_not_found'
handler500 = 'django.views.defaults.server_error'
-include = lambda urlconf_module: [urlconf_module]
+def include(arg, namespace=None, app_name=None):
+ if isinstance(arg, tuple):
+ # callable returning a namespace hint
+ if namespace:
+ raise ImproperlyConfigured('Cannot override the namespace for a dynamic module that provides a namespace')
+ urlconf_module, app_name, namespace = arg
+ else:
+ # No namespace hint - use manually provided namespace
+ urlconf_module = arg
+ return (urlconf_module, app_name, namespace)
def patterns(prefix, *args):
pattern_list = []
@@ -19,9 +28,10 @@ def patterns(prefix, *args):
return pattern_list
def url(regex, view, kwargs=None, name=None, prefix=''):
- if type(view) == list:
+ if isinstance(view, (list,tuple)):
# For include(...) processing.
- return RegexURLResolver(regex, view[0], kwargs)
+ urlconf_module, app_name, namespace = view
+ return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
else:
if isinstance(view, basestring):
if not view:
@@ -226,24 +226,24 @@ def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return update_wrapper(wrapper, view)
- info = self.admin_site.name, self.model._meta.app_label, self.model._meta.module_name
+ info = self.model._meta.app_label, self.model._meta.module_name
urlpatterns = patterns('',
url(r'^$',
wrap(self.changelist_view),
- name='%sadmin_%s_%s_changelist' % info),
+ name='%s_%s_changelist' % info),
url(r'^add/$',
wrap(self.add_view),
- name='%sadmin_%s_%s_add' % info),
+ name='%s_%s_add' % info),
url(r'^(.+)/history/$',
wrap(self.history_view),
- name='%sadmin_%s_%s_history' % info),
+ name='%s_%s_history' % info),
url(r'^(.+)/delete/$',
wrap(self.delete_view),
- name='%sadmin_%s_%s_delete' % info),
+ name='%s_%s_delete' % info),
url(r'^(.+)/$',
wrap(self.change_view),
- name='%sadmin_%s_%s_change' % info),
+ name='%s_%s_change' % info),
)
return urlpatterns
@@ -582,11 +582,12 @@ def render_change_form(self, request, context, add=False, change=False, form_url
'save_on_top': self.save_on_top,
'root_path': self.admin_site.root_path,
})
+ context_instance = template.RequestContext(request, current_app=self.admin_site.name)
return render_to_response(self.change_form_template or [
"admin/%s/%s/change_form.html" % (app_label, opts.object_name.lower()),
"admin/%s/change_form.html" % app_label,
"admin/change_form.html"
- ], context, context_instance=template.RequestContext(request))
+ ], context, context_instance=context_instance)
def response_add(self, request, obj, post_url_continue='../%s/'):
"""
@@ -977,11 +978,12 @@ def changelist_view(self, request, extra_context=None):
'actions_on_bottom': self.actions_on_bottom,
}
context.update(extra_context or {})
+ context_instance = template.RequestContext(request, current_app=self.admin_site.name)
return render_to_response(self.change_list_template or [
'admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()),
'admin/%s/change_list.html' % app_label,
'admin/change_list.html'
- ], context, context_instance=template.RequestContext(request))
+ ], context, context_instance=context_instance)
def delete_view(self, request, object_id, extra_context=None):
"The 'delete' admin view for this model."
@@ -1032,11 +1034,12 @@ def delete_view(self, request, object_id, extra_context=None):
"app_label": app_label,
}
context.update(extra_context or {})
+ context_instance = template.RequestContext(request, current_app=self.admin_site.name)
return render_to_response(self.delete_confirmation_template or [
"admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower()),
"admin/%s/delete_confirmation.html" % app_label,
"admin/delete_confirmation.html"
- ], context, context_instance=template.RequestContext(request))
+ ], context, context_instance=context_instance)
def history_view(self, request, object_id, extra_context=None):
"The 'history' admin view for this model."
@@ -1059,11 +1062,12 @@ def history_view(self, request, object_id, extra_context=None):
'app_label': app_label,
}
context.update(extra_context or {})
+ context_instance = template.RequestContext(request, current_app=self.admin_site.name)
return render_to_response(self.object_history_template or [
"admin/%s/%s/object_history.html" % (app_label, opts.object_name.lower()),
"admin/%s/object_history.html" % app_label,
"admin/object_history.html"
- ], context, context_instance=template.RequestContext(request))
+ ], context, context_instance=context_instance)
#
# DEPRECATED methods.
@@ -5,6 +5,7 @@
from django.contrib.auth import authenticate, login
from django.db.models.base import ModelBase
from django.core.exceptions import ImproperlyConfigured
+from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response
from django.utils.functional import update_wrapper
from django.utils.safestring import mark_safe
@@ -38,17 +39,14 @@ class AdminSite(object):
login_template = None
app_index_template = None
- def __init__(self, name=None):
+ def __init__(self, name=None, app_name='admin'):
self._registry = {} # model_class class -> admin_class instance
- # TODO Root path is used to calculate urls under the old root() method
- # in order to maintain backwards compatibility we are leaving that in
- # so root_path isn't needed, not sure what to do about this.
- self.root_path = 'admin/'
+ self.root_path = None
if name is None:
- name = ''
+ self.name = 'admin'
else:
- name += '_'
- self.name = name
+ self.name = name
+ self.app_name = app_name
self._actions = {'delete_selected': actions.delete_selected}
self._global_actions = self._actions.copy()
@@ -202,24 +200,24 @@ def wrapper(*args, **kwargs):
urlpatterns = patterns('',
url(r'^$',
wrap(self.index),
- name='%sadmin_index' % self.name),
+ name='index'),
url(r'^logout/$',
wrap(self.logout),
- name='%sadmin_logout'),
+ name='logout'),
url(r'^password_change/$',
wrap(self.password_change, cacheable=True),
- name='%sadmin_password_change' % self.name),
+ name='password_change'),
url(r'^password_change/done/$',
wrap(self.password_change_done, cacheable=True),
- name='%sadmin_password_change_done' % self.name),
+ name='password_change_done'),
url(r'^jsi18n/$',
wrap(self.i18n_javascript, cacheable=True),
- name='%sadmin_jsi18n' % self.name),
+ name='jsi18n'),
url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
'django.views.defaults.shortcut'),
url(r'^(?P<app_label>\w+)/$',
wrap(self.app_index),
- name='%sadmin_app_list' % self.name),
+ name='app_list')
)
# Add in each model's views.
@@ -231,16 +229,19 @@ def wrapper(*args, **kwargs):
return urlpatterns
def urls(self):
- return self.get_urls()
+ return self.get_urls(), self.app_name, self.name
urls = property(urls)
def password_change(self, request):
"""
Handles the "change password" task -- both form display and validation.
"""
from django.contrib.auth.views import password_change
- return password_change(request,
- post_change_redirect='%spassword_change/done/' % self.root_path)
+ if self.root_path is not None:
+ url = '%spassword_change/done/' % self.root_path
+ else:
+ url = reverse('admin:password_change_done', current_app=self.name)
+ return password_change(request, post_change_redirect=url)
def password_change_done(self, request):
"""
@@ -368,8 +369,9 @@ def index(self, request, extra_context=None):
'root_path': self.root_path,
}
context.update(extra_context or {})
+ context_instance = template.RequestContext(request, current_app=self.name)
return render_to_response(self.index_template or 'admin/index.html', context,
- context_instance=template.RequestContext(request)
+ context_instance=context_instance
)
index = never_cache(index)
@@ -382,8 +384,9 @@ def display_login_form(self, request, error_message='', extra_context=None):
'root_path': self.root_path,
}
context.update(extra_context or {})
+ context_instance = template.RequestContext(request, current_app=self.name)
return render_to_response(self.login_template or 'admin/login.html', context,
- context_instance=template.RequestContext(request)
+ context_instance=context_instance
)
def app_index(self, request, app_label, extra_context=None):
@@ -425,9 +428,10 @@ def app_index(self, request, app_label, extra_context=None):
'root_path': self.root_path,
}
context.update(extra_context or {})
+ context_instance = template.RequestContext(request, current_app=self.name)
return render_to_response(self.app_index_template or ('admin/%s/app_index.html' % app_label,
'admin/app_index.html'), context,
- context_instance=template.RequestContext(request)
+ context_instance=context_instance
)
def root(self, request, url):
@@ -23,7 +23,30 @@
{% block branding %}{% endblock %}
</div>
{% if user.is_authenticated and user.is_staff %}
- <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>
+ <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 %}
+ {% url admin:password_change as password_change_url %}
+ {% if password_change_url %}
+ <a href="{{ password_change_url }}">
+ {% else %}
+ <a href="{{ root_path }}password_change/">
+ {% endif %}
+ {% trans 'Change password' %}</a> /
+ {% url admin:logout as logout_url %}
+ {% if logout_url %}
+ <a href="{{ logout_url }}">
+ {% else %}
+ <a href="{{ root_path }}logout/">
+ {% endif %}
+ {% trans 'Log out' %}</a>
+ {% endblock %}
+ </div>
{% endif %}
{% block nav-global %}{% endblock %}
</div>
@@ -125,7 +125,7 @@ def render(self, name, value, attrs=None):
if value:
output.append(self.label_for_value(value))
return mark_safe(u''.join(output))
-
+
def base_url_parameters(self):
params = {}
if self.rel.limit_choices_to:
@@ -137,14 +137,14 @@ def base_url_parameters(self):
v = str(v)
items.append((k, v))
params.update(dict(items))
- return params
-
+ return params
+
def url_parameters(self):
from django.contrib.admin.views.main import TO_FIELD_VAR
params = self.base_url_parameters()
params.update({TO_FIELD_VAR: self.rel.get_related_field().name})
return params
-
+
def label_for_value(self, value):
key = self.rel.get_related_field().name
obj = self.rel.to._default_manager.get(**{key: value})
@@ -165,10 +165,10 @@ def render(self, name, value, attrs=None):
else:
value = ''
return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
-
+
def url_parameters(self):
return self.base_url_parameters()
-
+
def label_for_value(self, value):
return ''
@@ -222,8 +222,7 @@ def render(self, name, value, *args, **kwargs):
rel_to = self.rel.to
info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
try:
- related_info = (self.admin_site.name,) + info
- related_url = reverse('%sadmin_%s_%s_add' % related_info)
+ related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name)
except NoReverseMatch:
related_url = '../../../%s/%s/add/' % info
self.widget.choices = self.choices
@@ -1,6 +1,6 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="{{ root_path }}">Home</a> &rsaquo; Documentation</div>{% endblock %}
{% block title %}Documentation{% endblock %}
{% block content %}
@@ -22,11 +22,14 @@ class GenericSite(object):
name = 'my site'
def get_root_path():
- from django.contrib import admin
try:
- return urlresolvers.reverse(admin.site.root, args=[''])
+ return urlresolvers.reverse('admin:index')
except urlresolvers.NoReverseMatch:
- return getattr(settings, "ADMIN_SITE_ROOT_URL", "/admin/")
+ from django.contrib import admin
+ try:
+ return urlresolvers.reverse(admin.site.root, args=[''])
+ except urlresolvers.NoReverseMatch:
+ return getattr(settings, "ADMIN_SITE_ROOT_URL", "/admin/")
def doc_index(request):
if not utils.docutils_is_available:
@@ -179,7 +182,7 @@ def model_index(request):
def model_detail(request, app_label, model_name):
if not utils.docutils_is_available:
return missing_docutils_page(request)
-
+
# Get the model class.
try:
app_mod = models.get_app(app_label)
Oops, something went wrong.

0 comments on commit 8d48eaa

Please sign in to comment.