Ticket #10061: t10061-r11201.v3.diff
File t10061-r11201.v3.diff, 36.8 KB (added by , 15 years ago) |
---|
-
django/conf/urls/defaults.py
diff --git a/django/conf/urls/defaults.py b/django/conf/urls/defaults.py index 26cdd3e..572a7b0 100644
a b __all__ = ['handler404', 'handler500', 'include', 'patterns', 'url'] 6 6 handler404 = 'django.views.defaults.page_not_found' 7 7 handler500 = 'django.views.defaults.server_error' 8 8 9 include = lambda urlconf_module: [urlconf_module] 9 def include(arg, namespace=None, app_name=None): 10 if type(arg) == tuple: 11 # callable returning a namespace hint 12 if namespace: 13 raise ImproperlyConfigured('Cannot override the namespace for a dynamic module that provides a namespace') 14 urlconf_module, app_name, namespace = arg 15 else: 16 # No namespace hint - use manually provided namespace 17 urlconf_module = arg 18 return (urlconf_module, app_name, namespace) 10 19 11 20 def patterns(prefix, *args): 12 21 pattern_list = [] … … def patterns(prefix, *args): 19 28 return pattern_list 20 29 21 30 def url(regex, view, kwargs=None, name=None, prefix=''): 22 if type(view) == list:31 if type(view) == tuple: 23 32 # For include(...) processing. 24 return RegexURLResolver(regex, view[0], kwargs) 33 urlconf_module, app_name, namespace = view 34 return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace) 25 35 else: 26 36 if isinstance(view, basestring): 27 37 if not view: -
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 8297eca..0545409 100644
a b class ModelAdmin(BaseModelAdmin): 226 226 return self.admin_site.admin_view(view)(*args, **kwargs) 227 227 return update_wrapper(wrapper, view) 228 228 229 info = self. admin_site.name, self.model._meta.app_label, self.model._meta.module_name229 info = self.model._meta.app_label, self.model._meta.module_name 230 230 231 231 urlpatterns = patterns('', 232 232 url(r'^$', 233 233 wrap(self.changelist_view), 234 name='%s admin_%s_%s_changelist' % info),234 name='%s_%s_changelist' % info), 235 235 url(r'^add/$', 236 236 wrap(self.add_view), 237 name='%s admin_%s_%s_add' % info),237 name='%s_%s_add' % info), 238 238 url(r'^(.+)/history/$', 239 239 wrap(self.history_view), 240 name='%s admin_%s_%s_history' % info),240 name='%s_%s_history' % info), 241 241 url(r'^(.+)/delete/$', 242 242 wrap(self.delete_view), 243 name='%s admin_%s_%s_delete' % info),243 name='%s_%s_delete' % info), 244 244 url(r'^(.+)/$', 245 245 wrap(self.change_view), 246 name='%s admin_%s_%s_change' % info),246 name='%s_%s_change' % info), 247 247 ) 248 248 return urlpatterns 249 249 … … class ModelAdmin(BaseModelAdmin): 582 582 'save_on_top': self.save_on_top, 583 583 'root_path': self.admin_site.root_path, 584 584 }) 585 context_instance = template.RequestContext(request, app_name=self.admin_site.name) 585 586 return render_to_response(self.change_form_template or [ 586 587 "admin/%s/%s/change_form.html" % (app_label, opts.object_name.lower()), 587 588 "admin/%s/change_form.html" % app_label, 588 589 "admin/change_form.html" 589 ], context, context_instance= template.RequestContext(request))590 ], context, context_instance=context_instance) 590 591 591 592 def response_add(self, request, obj, post_url_continue='../%s/'): 592 593 """ … … class ModelAdmin(BaseModelAdmin): 977 978 'actions_on_bottom': self.actions_on_bottom, 978 979 } 979 980 context.update(extra_context or {}) 981 context_instance = template.RequestContext(request, app_name=self.admin_site.name) 980 982 return render_to_response(self.change_list_template or [ 981 983 'admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()), 982 984 'admin/%s/change_list.html' % app_label, 983 985 'admin/change_list.html' 984 ], context, context_instance= template.RequestContext(request))986 ], context, context_instance=context_instance) 985 987 986 988 def delete_view(self, request, object_id, extra_context=None): 987 989 "The 'delete' admin view for this model." … … class ModelAdmin(BaseModelAdmin): 1032 1034 "app_label": app_label, 1033 1035 } 1034 1036 context.update(extra_context or {}) 1037 context_instance = template.RequestContext(request, app_name=self.admin_site.name) 1035 1038 return render_to_response(self.delete_confirmation_template or [ 1036 1039 "admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower()), 1037 1040 "admin/%s/delete_confirmation.html" % app_label, 1038 1041 "admin/delete_confirmation.html" 1039 ], context, context_instance= template.RequestContext(request))1042 ], context, context_instance=context_instance) 1040 1043 1041 1044 def history_view(self, request, object_id, extra_context=None): 1042 1045 "The 'history' admin view for this model." … … class ModelAdmin(BaseModelAdmin): 1059 1062 'app_label': app_label, 1060 1063 } 1061 1064 context.update(extra_context or {}) 1065 context_instance = template.RequestContext(request, app_name=self.admin_site.name) 1062 1066 return render_to_response(self.object_history_template or [ 1063 1067 "admin/%s/%s/object_history.html" % (app_label, opts.object_name.lower()), 1064 1068 "admin/%s/object_history.html" % app_label, 1065 1069 "admin/object_history.html" 1066 ], context, context_instance= template.RequestContext(request))1070 ], context, context_instance=context_instance) 1067 1071 1068 1072 # 1069 1073 # DEPRECATED methods. -
django/contrib/admin/sites.py
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 6e9ef11..e161516 100644
a b from django.contrib.admin import actions 5 5 from django.contrib.auth import authenticate, login 6 6 from django.db.models.base import ModelBase 7 7 from django.core.exceptions import ImproperlyConfigured 8 from django.core.urlresolvers import reverse 8 9 from django.shortcuts import render_to_response 9 10 from django.utils.functional import update_wrapper 10 11 from django.utils.safestring import mark_safe … … class AdminSite(object): 38 39 login_template = None 39 40 app_index_template = None 40 41 41 def __init__(self, name=None ):42 def __init__(self, name=None, app_name='admin'): 42 43 self._registry = {} # model_class class -> admin_class instance 43 # TODO Root path is used to calculate urls under the old root() method 44 # in order to maintain backwards compatibility we are leaving that in 45 # so root_path isn't needed, not sure what to do about this. 46 self.root_path = 'admin/' 44 self.root_path = None 47 45 if name is None: 48 name = ''46 self.name = 'admin' 49 47 else: 50 name += '_'51 self. name =name48 self.name = name 49 self.app_name = app_name 52 50 self._actions = {'delete_selected': actions.delete_selected} 53 51 self._global_actions = self._actions.copy() 54 52 … … class AdminSite(object): 114 112 name = name or action.__name__ 115 113 self._actions[name] = action 116 114 self._global_actions[name] = action 117 115 118 116 def disable_action(self, name): 119 117 """ 120 118 Disable a globally-registered action. Raises KeyError for invalid names. 121 119 """ 122 120 del self._actions[name] 123 121 124 122 def get_action(self, name): 125 123 """ 126 124 Explicitally get a registered global action wheather it's enabled or 127 125 not. Raises KeyError for invalid names. 128 126 """ 129 127 return self._global_actions[name] 130 128 131 129 def actions(self): 132 130 """ 133 131 Get all the enabled actions as an iterable of (name, func). … … class AdminSite(object): 186 184 187 185 def get_urls(self): 188 186 from django.conf.urls.defaults import patterns, url, include 189 190 187 def wrap(view): 191 188 def wrapper(*args, **kwargs): 192 189 return self.admin_view(view)(*args, **kwargs) … … class AdminSite(object): 196 193 urlpatterns = patterns('', 197 194 url(r'^$', 198 195 wrap(self.index), 199 name=' %sadmin_index' % self.name),196 name='index'), 200 197 url(r'^logout/$', 201 198 wrap(self.logout), 202 name=' %sadmin_logout'),199 name='logout'), 203 200 url(r'^password_change/$', 204 201 wrap(self.password_change), 205 name=' %sadmin_password_change' % self.name),202 name='password_change'), 206 203 url(r'^password_change/done/$', 207 204 wrap(self.password_change_done), 208 name=' %sadmin_password_change_done' % self.name),205 name='password_change_done'), 209 206 url(r'^jsi18n/$', 210 207 wrap(self.i18n_javascript), 211 name=' %sadmin_jsi18n' % self.name),208 name='jsi18n'), 212 209 url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$', 213 210 'django.views.defaults.shortcut'), 214 211 url(r'^(?P<app_label>\w+)/$', 215 212 wrap(self.app_index), 216 name=' %sadmin_app_list' % self.name),213 name='app_list') 217 214 ) 218 215 219 216 # Add in each model's views. … … class AdminSite(object): 222 219 url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name), 223 220 include(model_admin.urls)) 224 221 ) 225 return urlpatterns 222 return urlpatterns, self.app_name, self.name 226 223 227 224 def urls(self): 228 225 return self.get_urls() … … class AdminSite(object): 233 230 Handles the "change password" task -- both form display and validation. 234 231 """ 235 232 from django.contrib.auth.views import password_change 236 return password_change(request, 237 post_change_redirect='%spassword_change/done/' % self.root_path) 233 if self.root_path is not None: 234 url = '%spassword_change/done/' % self.root_path 235 else: 236 url = reverse('%s:password_change_done' % self.name) 237 return password_change(request, post_change_redirect=url) 238 238 239 239 def password_change_done(self, request): 240 240 """ … … class AdminSite(object): 362 362 'root_path': self.root_path, 363 363 } 364 364 context.update(extra_context or {}) 365 context_instance = template.RequestContext(request, app_name=self.name) 365 366 return render_to_response(self.index_template or 'admin/index.html', context, 366 context_instance= template.RequestContext(request)367 context_instance=context_instance 367 368 ) 368 369 index = never_cache(index) 369 370 … … class AdminSite(object): 376 377 'root_path': self.root_path, 377 378 } 378 379 context.update(extra_context or {}) 380 context_instance = template.RequestContext(request, app_name=self.name) 379 381 return render_to_response(self.login_template or 'admin/login.html', context, 380 context_instance= template.RequestContext(request)382 context_instance=context_instance 381 383 ) 382 384 383 385 def app_index(self, request, app_label, extra_context=None): … … class AdminSite(object): 419 421 'root_path': self.root_path, 420 422 } 421 423 context.update(extra_context or {}) 424 context_instance = template.RequestContext(request, app_name=self.name) 422 425 return render_to_response(self.app_index_template or ('admin/%s/app_index.html' % app_label, 423 426 'admin/app_index.html'), context, 424 context_instance= template.RequestContext(request)427 context_instance=context_instance 425 428 ) 426 429 427 430 def root(self, request, url): -
django/contrib/admin/templates/admin/base.html
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html index 8cab439..9525728 100644
a b 23 23 {% block branding %}{% endblock %} 24 24 </div> 25 25 {% if user.is_authenticated and user.is_staff %} 26 <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> 26 <div id="user-tools"> 27 {% trans 'Welcome,' %} 28 <strong>{% firstof user.first_name user.username %}</strong>. 29 {% block userlinks %} 30 {% url django-admindocs-docroot as docsroot %} 31 {% if docsroot %} 32 <a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / 33 {% endif %} 34 {% url admin:password_change as password_change_url %} 35 {% if password_change_url %} 36 <a href="{{ password_change_url }}"> 37 {% else %} 38 <a href="{{ root_path }}password_change/"> 39 {% endif %} 40 {% trans 'Change password' %}</a> / 41 {% url admin:logout as logout_url %} 42 {% if logout_url %} 43 <a href="{{ logout_url }}"> 44 {% else %} 45 <a href="{{ root_path }}logout/"> 46 {% endif %} 47 {% trans 'Log out' %}</a> 48 {% endblock %} 49 </div> 27 50 {% endif %} 28 51 {% block nav-global %}{% endblock %} 29 52 </div> -
django/contrib/admin/widgets.py
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 7ae5e64..778cf4a 100644
a b class ForeignKeyRawIdWidget(forms.TextInput): 125 125 if value: 126 126 output.append(self.label_for_value(value)) 127 127 return mark_safe(u''.join(output)) 128 128 129 129 def base_url_parameters(self): 130 130 params = {} 131 131 if self.rel.limit_choices_to: … … class ForeignKeyRawIdWidget(forms.TextInput): 137 137 v = str(v) 138 138 items.append((k, v)) 139 139 params.update(dict(items)) 140 return params 141 140 return params 141 142 142 def url_parameters(self): 143 143 from django.contrib.admin.views.main import TO_FIELD_VAR 144 144 params = self.base_url_parameters() 145 145 params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) 146 146 return params 147 147 148 148 def label_for_value(self, value): 149 149 key = self.rel.get_related_field().name 150 150 obj = self.rel.to._default_manager.get(**{key: value}) … … class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 165 165 else: 166 166 value = '' 167 167 return super(ManyToManyRawIdWidget, self).render(name, value, attrs) 168 168 169 169 def url_parameters(self): 170 170 return self.base_url_parameters() 171 171 172 172 def label_for_value(self, value): 173 173 return '' 174 174 … … class RelatedFieldWidgetWrapper(forms.Widget): 222 222 rel_to = self.rel.to 223 223 info = (rel_to._meta.app_label, rel_to._meta.object_name.lower()) 224 224 try: 225 related_info = (self.admin_site.name,) + info 226 related_url = reverse('%sadmin_%s_%s_add' % related_info) 225 related_url = reverse('admin:%s_%s_add' % info, app_name=self.admin_site.name) 227 226 except NoReverseMatch: 228 227 related_url = '../../../%s/%s/add/' % info 229 228 self.widget.choices = self.choices -
django/contrib/admindocs/templates/admin_doc/index.html
diff --git a/django/contrib/admindocs/templates/admin_doc/index.html b/django/contrib/admindocs/templates/admin_doc/index.html index 242fc73..a8b21c3 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% block breadcrumbs %}<div class="breadcrumbs"><a href=" ../">Home</a> › Documentation</div>{% endblock %}3 {% block breadcrumbs %}<div class="breadcrumbs"><a href="{{ root_path }}">Home</a> › Documentation</div>{% endblock %} 4 4 {% block title %}Documentation{% endblock %} 5 5 6 6 {% block content %} -
django/contrib/admindocs/views.py
diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 4f22fe0..063aac9 100644
a b class GenericSite(object): 22 22 name = 'my site' 23 23 24 24 def get_root_path(): 25 from django.contrib import admin 26 try: 27 return urlresolvers.reverse(admin.site.root, args=['']) 28 except urlresolvers.NoReverseMatch: 29 return getattr(settings, "ADMIN_SITE_ROOT_URL", "/admin/") 25 return urlresolvers.reverse('admin:index') 30 26 31 27 def doc_index(request): 32 28 if not utils.docutils_is_available: … … model_index = staff_member_required(model_index) 179 175 def model_detail(request, app_label, model_name): 180 176 if not utils.docutils_is_available: 181 177 return missing_docutils_page(request) 182 178 183 179 # Get the model class. 184 180 try: 185 181 app_mod = models.get_app(app_label) -
django/core/urlresolvers.py
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index 10e97bb..823cd77 100644
a b class RegexURLPattern(object): 139 139 callback = property(_get_callback) 140 140 141 141 class RegexURLResolver(object): 142 def __init__(self, regex, urlconf_name, default_kwargs=None ):142 def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None): 143 143 # regex is a string representing a regular expression. 144 144 # urlconf_name is a string representing the module containing URLconfs. 145 145 self.regex = re.compile(regex, re.UNICODE) … … class RegexURLResolver(object): 148 148 self._urlconf_module = self.urlconf_name 149 149 self.callback = None 150 150 self.default_kwargs = default_kwargs or {} 151 self._reverse_dict = MultiValueDict() 151 self.namespace = namespace 152 self.app_name = app_name 153 self._reverse_dict = None 154 self._namespace_dict = None 155 self._app_dict = None 152 156 153 157 def __repr__(self): 154 return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, self.regex.pattern) 155 156 def _get_reverse_dict(self): 157 if not self._reverse_dict: 158 lookups = MultiValueDict() 159 for pattern in reversed(self.url_patterns): 160 p_pattern = pattern.regex.pattern 161 if p_pattern.startswith('^'): 162 p_pattern = p_pattern[1:] 163 if isinstance(pattern, RegexURLResolver): 158 return '<%s %s (%s:%s) %s>' % (self.__class__.__name__, self.urlconf_name, self.app_name, self.namespace, self.regex.pattern) 159 160 def _populate(self): 161 lookups = MultiValueDict() 162 namespaces = {} 163 apps = {} 164 for pattern in reversed(self.url_patterns): 165 p_pattern = pattern.regex.pattern 166 if p_pattern.startswith('^'): 167 p_pattern = p_pattern[1:] 168 if isinstance(pattern, RegexURLResolver): 169 if pattern.namespace: 170 namespaces[pattern.namespace] = (p_pattern, pattern) 171 if pattern.app_name: 172 apps.setdefault(pattern.app_name, []).append(pattern.namespace) 173 else: 164 174 parent = normalize(pattern.regex.pattern) 165 175 for name in pattern.reverse_dict: 166 176 for matches, pat in pattern.reverse_dict.getlist(name): … … class RegexURLResolver(object): 168 178 for piece, p_args in parent: 169 179 new_matches.extend([(piece + suffix, p_args + args) for (suffix, args) in matches]) 170 180 lookups.appendlist(name, (new_matches, p_pattern + pat)) 171 else: 172 bits = normalize(p_pattern) 173 lookups.appendlist(pattern.callback, (bits, p_pattern)) 174 lookups.appendlist(pattern.name, (bits, p_pattern)) 175 self._reverse_dict = lookups 181 for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items(): 182 namespaces[namespace] = (p_pattern + prefix, sub_pattern) 183 for app_name, namespace_list in pattern.app_dict.items(): 184 apps.setdefault(app_name, []).extend(namespace_list) 185 else: 186 bits = normalize(p_pattern) 187 lookups.appendlist(pattern.callback, (bits, p_pattern)) 188 lookups.appendlist(pattern.name, (bits, p_pattern)) 189 self._reverse_dict = lookups 190 self._namespace_dict = namespaces 191 self._app_dict = apps 192 193 def _get_reverse_dict(self): 194 if self._reverse_dict is None: 195 self._populate() 176 196 return self._reverse_dict 177 197 reverse_dict = property(_get_reverse_dict) 178 198 199 def _get_namespace_dict(self): 200 if self._namespace_dict is None: 201 self._populate() 202 return self._namespace_dict 203 namespace_dict = property(_get_namespace_dict) 204 205 def _get_app_dict(self): 206 if self._app_dict is None: 207 self._populate() 208 return self._app_dict 209 app_dict = property(_get_app_dict) 210 179 211 def resolve(self, path): 180 212 tried = [] 181 213 match = self.regex.search(path) … … class RegexURLResolver(object): 261 293 def resolve(path, urlconf=None): 262 294 return get_resolver(urlconf).resolve(path) 263 295 264 def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None): 296 def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, app_name=None): 297 resolver = get_resolver(urlconf) 265 298 args = args or [] 266 299 kwargs = kwargs or {} 300 267 301 if prefix is None: 268 302 prefix = get_script_prefix() 269 return iri_to_uri(u'%s%s' % (prefix, get_resolver(urlconf).reverse(viewname, 303 304 if not isinstance(viewname, basestring): 305 view = viewname 306 else: 307 parts = viewname.split(':') 308 parts.reverse() 309 view = parts[0] 310 path = parts[1:] 311 312 resolved_path = [] 313 while path: 314 ns = path.pop() 315 316 # Lookup the name to see if it could be an app identifier 317 try: 318 app_list = resolver.app_dict[ns] 319 # Yes! Path part matches an app in the current Resolver 320 if app_name and app_name in app_list: 321 # If we are reversing for a particular app, use that namespace 322 ns = app_name 323 elif ns not in app_list: 324 # The name isn't shared by one of the instances (i.e., the default) 325 # so just pick the first instance as the default. 326 ns = app_list[0] 327 except KeyError: 328 pass 329 330 try: 331 extra, resolver = resolver.namespace_dict[ns] 332 resolved_path.append(ns) 333 prefix = prefix + extra 334 except KeyError, key: 335 if resolved_path: 336 raise NoReverseMatch("%s is not a registered namespace inside '%s'" % (key, ':'.join(resolved_path))) 337 else: 338 raise NoReverseMatch("%s is not a registered namespace" % key) 339 340 return iri_to_uri(u'%s%s' % (prefix, resolver.reverse(view, 270 341 *args, **kwargs))) 271 342 272 343 def clear_url_caches(): -
django/template/context.py
diff --git a/django/template/context.py b/django/template/context.py index 0ccb5fa..e79af4d 100644
a b class ContextPopException(Exception): 9 9 10 10 class Context(object): 11 11 "A stack container for variable context" 12 def __init__(self, dict_=None, autoescape=True ):12 def __init__(self, dict_=None, autoescape=True, app_name=None): 13 13 dict_ = dict_ or {} 14 14 self.dicts = [dict_] 15 15 self.autoescape = autoescape 16 self.app_name = app_name 16 17 17 18 def __repr__(self): 18 19 return repr(self.dicts) … … class RequestContext(Context): 96 97 Additional processors can be specified as a list of callables 97 98 using the "processors" keyword argument. 98 99 """ 99 def __init__(self, request, dict=None, processors=None ):100 Context.__init__(self, dict )100 def __init__(self, request, dict=None, processors=None, app_name=None): 101 Context.__init__(self, dict, app_name=app_name) 101 102 if processors is None: 102 103 processors = () 103 104 else: -
django/template/defaulttags.py
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 7d91cd6..a61e965 100644
a b class URLNode(Node): 367 367 # {% url ... as var %} construct in which cause return nothing. 368 368 url = '' 369 369 try: 370 url = reverse(self.view_name, args=args, kwargs=kwargs )370 url = reverse(self.view_name, args=args, kwargs=kwargs, app_name=context.app_name) 371 371 except NoReverseMatch, e: 372 372 if settings.SETTINGS_MODULE: 373 373 project_name = settings.SETTINGS_MODULE.split('.')[0] 374 374 try: 375 375 url = reverse(project_name + '.' + self.view_name, 376 args=args, kwargs=kwargs )376 args=args, kwargs=kwargs, app_name=context.app_name) 377 377 except NoReverseMatch: 378 378 if self.asvar is None: 379 379 # Re-raise the original exception, not the one with 380 # the path relative to the project. This makes a 380 # the path relative to the project. This makes a 381 381 # better error message. 382 382 raise e 383 383 else: -
tests/regressiontests/admin_views/customadmin.py
diff --git a/tests/regressiontests/admin_views/customadmin.py b/tests/regressiontests/admin_views/customadmin.py index 70e87eb..4aa781e 100644
a b import models 10 10 class Admin2(admin.AdminSite): 11 11 login_template = 'custom_admin/login.html' 12 12 index_template = 'custom_admin/index.html' 13 13 14 14 # A custom index view. 15 15 def index(self, request, extra_context=None): 16 16 return super(Admin2, self).index(request, {'foo': '*bar*'}) 17 17 18 18 def get_urls(self): 19 base_patterns, app_name, name = super(Admin2, self).get_urls() 19 20 return patterns('', 20 21 (r'^my_view/$', self.admin_view(self.my_view)), 21 ) + super(Admin2, self).get_urls()22 22 ) + base_patterns, app_name, name 23 23 24 def my_view(self, request): 24 25 return HttpResponse("Django is a magical pony!") 25 26 26 27 site = Admin2(name="admin2") 27 28 28 29 site.register(models.Article, models.ArticleAdmin) -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 99168fd..3fc145b 100644
a b class AdminViewBasicTest(TestCase): 204 204 response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'}) 205 205 self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit) 206 206 207 def testLogoutAndPasswordChangeURLs(self): 208 response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit) 209 self.failIf('<a href="/test_admin/%s/logout/">' % self.urlbit not in response.content) 210 self.failIf('<a href="/test_admin/%s/password_change/">' % self.urlbit not in response.content) 211 207 212 def testNamedGroupFieldChoicesChangeList(self): 208 213 """ 209 214 Ensures the admin changelist shows correct values in the relevant column -
tests/regressiontests/admin_widgets/widgetadmin.py
diff --git a/tests/regressiontests/admin_widgets/widgetadmin.py b/tests/regressiontests/admin_widgets/widgetadmin.py index bd68954..9257c30 100644
a b class CarTireAdmin(admin.ModelAdmin): 19 19 return db_field.formfield(**kwargs) 20 20 return super(CarTireAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) 21 21 22 site = WidgetAdmin( )22 site = WidgetAdmin(name='widget-admin') 23 23 24 24 site.register(models.User) 25 25 site.register(models.Car, CarAdmin) -
new file tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py
diff --git a/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py new file mode 100644 index 0000000..0731906
- + 1 from django.conf.urls.defaults import * 2 from namespace_urls import URLObject 3 4 testobj3 = URLObject('testapp', 'test-ns3') 5 6 urlpatterns = patterns('regressiontests.urlpatterns_reverse.views', 7 url(r'^normal/$', 'empty_view', name='inc-normal-view'), 8 url(r'^normal/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='inc-normal-view'), 9 10 (r'^test3/', include(testobj3.urls)), 11 (r'^ns-included3/', include('regressiontests.urlpatterns_reverse.included_urls', namespace='inc-ns3')), 12 ) 13 -
new file tests/regressiontests/urlpatterns_reverse/namespace_urls.py
diff --git a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py new file mode 100644 index 0000000..27cc7f7
- + 1 from django.conf.urls.defaults import * 2 3 class URLObject(object): 4 def __init__(self, app_name, namespace): 5 self.app_name = app_name 6 self.namespace = namespace 7 8 def urls(self): 9 return patterns('', 10 url(r'^inner/$', 'empty_view', name='urlobject-view'), 11 url(r'^inner/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='urlobject-view'), 12 ), self.app_name, self.namespace 13 urls = property(urls) 14 15 testobj1 = URLObject('testapp', 'test-ns1') 16 testobj2 = URLObject('testapp', 'test-ns2') 17 default_testobj = URLObject('testapp', 'testapp') 18 19 otherobj1 = URLObject('nodefault', 'other-ns1') 20 otherobj2 = URLObject('nodefault', 'other-ns2') 21 22 urlpatterns = patterns('regressiontests.urlpatterns_reverse.views', 23 url(r'^normal/$', 'empty_view', name='normal-view'), 24 url(r'^normal/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='normal-view'), 25 26 (r'^test1/', include(testobj1.urls)), 27 (r'^test2/', include(testobj2.urls)), 28 (r'^default/', include(default_testobj.urls)), 29 30 (r'^other1/', include(otherobj1.urls)), 31 (r'^other2/', include(otherobj2.urls)), 32 33 (r'^ns-included1/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns1')), 34 (r'^ns-included2/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns2')), 35 36 (r'^included/', include('regressiontests.urlpatterns_reverse.included_namespace_urls')), 37 38 ) -
tests/regressiontests/urlpatterns_reverse/tests.py
diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py index 9def6b2..68e34eb 100644
a b class ReverseShortcutTests(TestCase): 158 158 res = redirect('/foo/') 159 159 self.assertEqual(res['Location'], '/foo/') 160 160 res = redirect('http://example.com/') 161 self.assertEqual(res['Location'], 'http://example.com/') 162 No newline at end of file 161 self.assertEqual(res['Location'], 'http://example.com/') 162 163 164 class NamespaceTests(TestCase): 165 urls = 'regressiontests.urlpatterns_reverse.namespace_urls' 166 167 def test_ambiguous_object(self): 168 "Names deployed via dynamic URL objects that require namespaces can't be resolved" 169 self.assertRaises(NoReverseMatch, reverse, 'urlobject-view') 170 self.assertRaises(NoReverseMatch, reverse, 'urlobject-view', args=[37,42]) 171 self.assertRaises(NoReverseMatch, reverse, 'urlobject-view', kwargs={'arg1':42, 'arg2':37}) 172 173 def test_ambiguous_urlpattern(self): 174 "Names deployed via dynamic URL objects that require namespaces can't be resolved" 175 self.assertRaises(NoReverseMatch, reverse, 'inner-nothing') 176 self.assertRaises(NoReverseMatch, reverse, 'inner-nothing', args=[37,42]) 177 self.assertRaises(NoReverseMatch, reverse, 'inner-nothing', kwargs={'arg1':42, 'arg2':37}) 178 179 def test_non_existent_namespace(self): 180 "Non-existent namespaces raise errors" 181 self.assertRaises(NoReverseMatch, reverse, 'blahblah:urlobject-view') 182 self.assertRaises(NoReverseMatch, reverse, 'test-ns1:blahblah:urlobject-view') 183 184 def test_normal_name(self): 185 "Normal lookups work as expected" 186 self.assertEquals('/normal/', reverse('normal-view')) 187 self.assertEquals('/normal/37/42/', reverse('normal-view', args=[37,42])) 188 self.assertEquals('/normal/42/37/', reverse('normal-view', kwargs={'arg1':42, 'arg2':37})) 189 190 def test_simple_included_name(self): 191 "Normal lookups work on names included from other patterns" 192 self.assertEquals('/included/normal/', reverse('inc-normal-view')) 193 self.assertEquals('/included/normal/37/42/', reverse('inc-normal-view', args=[37,42])) 194 self.assertEquals('/included/normal/42/37/', reverse('inc-normal-view', kwargs={'arg1':42, 'arg2':37})) 195 196 def test_namespace_object(self): 197 "Dynamic URL objects can be found using a namespace" 198 self.assertEquals('/test1/inner/', reverse('test-ns1:urlobject-view')) 199 self.assertEquals('/test1/inner/37/42/', reverse('test-ns1:urlobject-view', args=[37,42])) 200 self.assertEquals('/test1/inner/42/37/', reverse('test-ns1:urlobject-view', kwargs={'arg1':42, 'arg2':37})) 201 202 def test_embedded_namespace_object(self): 203 "Namespaces can be installed anywhere in the URL pattern tree" 204 self.assertEquals('/included/test3/inner/', reverse('test-ns3:urlobject-view')) 205 self.assertEquals('/included/test3/inner/37/42/', reverse('test-ns3:urlobject-view', args=[37,42])) 206 self.assertEquals('/included/test3/inner/42/37/', reverse('test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37})) 207 208 def test_namespace_pattern(self): 209 "Namespaces can be applied to include()'d urlpatterns" 210 self.assertEquals('/ns-included1/normal/', reverse('inc-ns1:inc-normal-view')) 211 self.assertEquals('/ns-included1/normal/37/42/', reverse('inc-ns1:inc-normal-view', args=[37,42])) 212 self.assertEquals('/ns-included1/normal/42/37/', reverse('inc-ns1:inc-normal-view', kwargs={'arg1':42, 'arg2':37})) 213 214 def test_multiple_namespace_pattern(self): 215 "Namespaces can be embedded" 216 self.assertEquals('/ns-included1/test3/inner/', reverse('inc-ns1:test-ns3:urlobject-view')) 217 self.assertEquals('/ns-included1/test3/inner/37/42/', reverse('inc-ns1:test-ns3:urlobject-view', args=[37,42])) 218 self.assertEquals('/ns-included1/test3/inner/42/37/', reverse('inc-ns1:test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37})) 219 220 def test_app_lookup_object(self): 221 "A default application namespace can be used for lookup" 222 self.assertEquals('/default/inner/', reverse('testapp:urlobject-view')) 223 self.assertEquals('/default/inner/37/42/', reverse('testapp:urlobject-view', args=[37,42])) 224 self.assertEquals('/default/inner/42/37/', reverse('testapp:urlobject-view', kwargs={'arg1':42, 'arg2':37})) 225 226 def test_app_lookup_object_with_default(self): 227 "A default application namespace is sensitive to the 'current' app can be used for lookup" 228 self.assertEquals('/included/test3/inner/', reverse('testapp:urlobject-view', app_name='test-ns3')) 229 self.assertEquals('/included/test3/inner/37/42/', reverse('testapp:urlobject-view', args=[37,42], app_name='test-ns3')) 230 self.assertEquals('/included/test3/inner/42/37/', reverse('testapp:urlobject-view', kwargs={'arg1':42, 'arg2':37}, app_name='test-ns3')) 231 232 def test_app_lookup_object_without_default(self): 233 "An application namespace without a default is sensitive to the 'current' app can be used for lookup" 234 self.assertEquals('/other2/inner/', reverse('nodefault:urlobject-view')) 235 self.assertEquals('/other2/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42])) 236 self.assertEquals('/other2/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37})) 237 238 self.assertEquals('/other1/inner/', reverse('nodefault:urlobject-view', app_name='other-ns1')) 239 self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], app_name='other-ns1')) 240 self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, app_name='other-ns1')) 241