mirror of
https://github.com/django/django.git
synced 2025-11-07 07:15:35 +00:00
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.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11740 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user