diff options
| author | Brian Rosner <brosner@gmail.com> | 2009-11-16 01:59:54 +0000 |
|---|---|---|
| committer | Brian Rosner <brosner@gmail.com> | 2009-11-16 01:59:54 +0000 |
| commit | 4cba436269947df3124fa55c6c53ae170ce596c5 (patch) | |
| tree | 8bac961de76bb7212f717b09cdb39897e2cda3ec /django | |
| parent | 7f2f6bc8631a4f6952e11a824f423f3bac760443 (diff) | |
[1.1.X] Fixed #5034 -- honor request.urlconf in reverse and resolve.
This enables {% url %} to honor request.urlconf set from process_request
middleware methods.
Thanks SmileyChris for the initial patch work.
Backport of [11740] from trunk
git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@11741 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
| -rw-r--r-- | django/core/handlers/base.py | 103 | ||||
| -rw-r--r-- | django/core/urlresolvers.py | 30 |
2 files changed, 87 insertions, 46 deletions
diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index e6ef6e2f9e..f144ce4bb1 100644 --- a/django/core/handlers/base.py +++ b/django/core/handlers/base.py @@ -68,6 +68,9 @@ class BaseHandler(object): from django.core import exceptions, urlresolvers from django.conf import settings + # Reset the urlconf for this thread. + urlresolvers.set_urlconf(None) + # Apply request middleware for middleware_method in self._request_middleware: response = middleware_method(request) @@ -77,61 +80,69 @@ class BaseHandler(object): # Get urlconf from request object, if available. Otherwise use default. urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF) + # Set the urlconf for this thread to the one specified above. + urlresolvers.set_urlconf(urlconf) + resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) try: - callback, callback_args, callback_kwargs = resolver.resolve( - request.path_info) - - # Apply view middleware - for middleware_method in self._view_middleware: - response = middleware_method(request, callback, callback_args, callback_kwargs) - if response: - return response - try: - response = callback(request, *callback_args, **callback_kwargs) - except Exception, e: - # If the view raised an exception, run it through exception - # middleware, and if the exception middleware returns a - # response, use that. Otherwise, reraise the exception. - for middleware_method in self._exception_middleware: - response = middleware_method(request, e) + callback, callback_args, callback_kwargs = resolver.resolve( + request.path_info) + + # Apply view middleware + for middleware_method in self._view_middleware: + response = middleware_method(request, callback, callback_args, callback_kwargs) if response: return response - raise - # Complain if the view returned None (a common error). - if response is None: try: - view_name = callback.func_name # If it's a function - except AttributeError: - view_name = callback.__class__.__name__ + '.__call__' # If it's a class - raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name) + response = callback(request, *callback_args, **callback_kwargs) + except Exception, e: + # If the view raised an exception, run it through exception + # middleware, and if the exception middleware returns a + # response, use that. Otherwise, reraise the exception. + for middleware_method in self._exception_middleware: + response = middleware_method(request, e) + if response: + return response + raise - return response - except http.Http404, e: - if settings.DEBUG: - from django.views import debug - return debug.technical_404_response(request, e) - else: - try: - callback, param_dict = resolver.resolve404() - return callback(request, **param_dict) - except: + # Complain if the view returned None (a common error). + if response is None: try: - return self.handle_uncaught_exception(request, resolver, sys.exc_info()) - finally: - receivers = signals.got_request_exception.send(sender=self.__class__, request=request) - except exceptions.PermissionDenied: - return http.HttpResponseForbidden('<h1>Permission denied</h1>') - except SystemExit: - # Allow sys.exit() to actually exit. See tickets #1023 and #4701 - raise - except: # Handle everything else, including SuspiciousOperation, etc. - # Get the exception info now, in case another exception is thrown later. - exc_info = sys.exc_info() - receivers = signals.got_request_exception.send(sender=self.__class__, request=request) - return self.handle_uncaught_exception(request, resolver, exc_info) + view_name = callback.func_name # If it's a function + except AttributeError: + view_name = callback.__class__.__name__ + '.__call__' # If it's a class + raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name) + + return response + except http.Http404, e: + if settings.DEBUG: + from django.views import debug + return debug.technical_404_response(request, e) + else: + try: + callback, param_dict = resolver.resolve404() + return callback(request, **param_dict) + except: + try: + return self.handle_uncaught_exception(request, resolver, sys.exc_info()) + finally: + receivers = signals.got_request_exception.send(sender=self.__class__, request=request) + except exceptions.PermissionDenied: + return http.HttpResponseForbidden('<h1>Permission denied</h1>') + except SystemExit: + # Allow sys.exit() to actually exit. See tickets #1023 and #4701 + raise + except: # Handle everything else, including SuspiciousOperation, etc. + # Get the exception info now, in case another exception is thrown later. + exc_info = sys.exc_info() + receivers = signals.got_request_exception.send(sender=self.__class__, request=request) + return self.handle_uncaught_exception(request, resolver, exc_info) + finally: + # Reset URLconf for this thread on the way out for complete + # isolation of request.urlconf + urlresolvers.set_urlconf(None) def handle_uncaught_exception(self, request, resolver, exc_info): """ diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index eedb8f126c..a924afeaf8 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -10,6 +10,7 @@ a string) and returns a tuple in this format: import re from django.http import Http404 +from django.conf import settings from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist from django.utils.datastructures import MultiValueDict from django.utils.encoding import iri_to_uri, force_unicode, smart_str @@ -32,6 +33,9 @@ _callable_cache = {} # Maps view and url pattern names to their view functions. # be empty. _prefixes = {} +# Overridden URLconfs for each thread are stored here. +_urlconfs = {} + class Resolver404(Http404): pass @@ -300,9 +304,13 @@ class RegexURLResolver(object): "arguments '%s' not found." % (lookup_view_s, args, kwargs)) def resolve(path, urlconf=None): + if urlconf is None: + urlconf = get_urlconf() return get_resolver(urlconf).resolve(path) def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None): + if urlconf is None: + urlconf = get_urlconf() resolver = get_resolver(urlconf) args = args or [] kwargs = kwargs or {} @@ -371,3 +379,25 @@ def get_script_prefix(): """ return _prefixes.get(currentThread(), u'/') +def set_urlconf(urlconf_name): + """ + Sets the URLconf for the current thread (overriding the default one in + settings). Set to None to revert back to the default. + """ + thread = currentThread() + if urlconf_name: + _urlconfs[thread] = urlconf_name + else: + # faster than wrapping in a try/except + if thread in _urlconfs: + del _urlconfs[thread] + +def get_urlconf(default=None): + """ + Returns the root URLconf to use for the current thread if it has been + changed from the default one. + """ + thread = currentThread() + if thread in _urlconfs: + return _urlconfs[thread] + return default |
