Index: django/core/urlresolvers.py
===================================================================
--- django/core/urlresolvers.py	(revision 11590)
+++ django/core/urlresolvers.py	(working copy)
@@ -32,6 +32,9 @@
 # be empty.
 _prefixes = {}
 
+# Overridden URLconfs for each thread are stored here. 
+_urlconfs = {}
+
 class Resolver404(Http404):
     pass
 
@@ -300,9 +303,13 @@
                 "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 +378,26 @@
     """
     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: 
+        # This is a lot 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() 
+    # It's faster to check first than to do _urlconfs.get(thread) 
+    if thread in _urlconfs: 
+        return _urlconfs[thread] 
+    return default
\ No newline at end of file
Index: django/core/handlers/base.py
===================================================================
--- django/core/handlers/base.py	(revision 11590)
+++ django/core/handlers/base.py	(working copy)
@@ -67,15 +67,30 @@
         "Returns an HttpResponse object for the given HttpRequest"
         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)
             if response:
                 return response
 
-        # Get urlconf from request object, if available.  Otherwise use default.
-        urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
+        # Get overridden urlconf for this thread, if available. Otherwise use
+        # default.
+        urlconf = urlresolvers.get_urlconf()
+        if urlconf is None:
+            # Get urlconf from request object, if available (deprecated).
+            if hasattr(request, 'urlconf'):
+                import warnings
+                warnings.warn("The 'request.urlconf' attribute is deprecated. "
+                              "Use the 'django.core.urlresolvers::set_urlconf'"
+                              " method instead.", DeprecationWarning)
+                urlconf = request.urlconf
+                urlresolvers.set_urlconf(urlconf)
+            else:
+                urlconf = settings.ROOT_URLCONF
 
         resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
         try:
@@ -132,6 +147,9 @@
             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 the urlconf for this thread.
+            urlresolvers.set_urlconf(None)
 
     def handle_uncaught_exception(self, request, resolver, exc_info):
         """
Index: tests/regressiontests/urlpatterns_reverse/tests.py
===================================================================
--- tests/regressiontests/urlpatterns_reverse/tests.py	(revision 11590)
+++ tests/regressiontests/urlpatterns_reverse/tests.py	(working copy)
@@ -14,13 +14,19 @@
 ImproperlyConfigured: The included urlconf regressiontests.urlpatterns_reverse.no_urls doesn't have any patterns in it
 """}
 
+import re 
 import unittest
 
+from django.conf import settings
 from django.core.urlresolvers import reverse, resolve, NoReverseMatch, Resolver404
 from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
 from django.shortcuts import redirect
 from django.test import TestCase
 
+import urlconf_outer
+import urlconf_inner
+import middleware
+
 test_data = (
     ('places', '/places/3/', [3], {}),
     ('places', '/places/3/', ['3'], {}),
@@ -239,3 +245,35 @@
         self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], current_app='other-ns1'))
         self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1'))
 
+
+class SetUrlConf(TestCase): 
+    def setUp(self): 
+        self.root_urlconf = settings.ROOT_URLCONF 
+        self.middleware_classes = settings.MIDDLEWARE_CLASSES 
+        settings.ROOT_URLCONF = urlconf_outer.__name__ 
+        
+    def tearDown(self): 
+        settings.ROOT_URLCONF = self.root_urlconf 
+        settings.MIDDLEWARE_CLASSES = self.middleware_classes 
+        
+    def test_handler(self): 
+        response = self.client.get('/test/me/') 
+        self.assertEqual(response.status_code, 200) 
+        self.assertEqual(response.content, 'outer:/test/me/,' 
+                                           'inner:/inner_urlconf/second_test/') 
+        response = self.client.get('/inner_urlconf/second_test/') 
+        self.assertEqual(response.status_code, 200) 
+        response = self.client.get('/second_test/') 
+        self.assertEqual(response.status_code, 404) 
+        
+    def test_handler_overridden(self): 
+        settings.MIDDLEWARE_CLASSES += ( 
+            '%s.ChangeUrlconfMiddleware' % middleware.__name__, 
+        ) 
+        response = self.client.get('/test/me/') 
+        self.assertEqual(response.status_code, 404) 
+        response = self.client.get('/inner_urlconf/second_test/') 
+        self.assertEqual(response.status_code, 404) 
+        response = self.client.get('/second_test/') 
+        self.assertEqual(response.status_code, 200) 
+        self.assertEqual(response.content, 'outer:,inner:/second_test/')
\ No newline at end of file
Index: docs/topics/http/urls.txt
===================================================================
--- docs/topics/http/urls.txt	(revision 11590)
+++ docs/topics/http/urls.txt	(working copy)
@@ -39,9 +39,10 @@
 algorithm the system follows to determine which Python code to execute:
 
     1. Django determines the root URLconf module to use. Ordinarily,
-       this is the value of the ``ROOT_URLCONF`` setting, but if the incoming
-       ``HttpRequest`` object has an attribute called ``urlconf``, its value
-       will be used in place of the ``ROOT_URLCONF`` setting.
+       this is the value of the ``ROOT_URLCONF`` setting, this can be overridden 
+       per request by calling the ``set_urlconf`` method found in 
+       ``django.core.urlresolvers`` (passing in the value to be used in place of 
+       the ``ROOT_URLCONF`` setting).
 
     2. Django loads that Python module and looks for the variable
        ``urlpatterns``. This should be a Python list, in the format returned by
Index: docs/ref/settings.txt
===================================================================
--- docs/ref/settings.txt	(revision 11590)
+++ docs/ref/settings.txt	(working copy)
@@ -804,10 +804,10 @@
 
 Default: Not defined
 
-A string representing the full Python import path to your root URLconf. For example:
-``"mydjangoapps.urls"``. Can be overridden on a per-request basis by
-setting the attribute ``urlconf`` on the incoming ``HttpRequest``
-object. See :ref:`how-django-processes-a-request` for details.
+A string representing the full Python import path to your root URLconf. For
+example: ``"mydjangoapps.urls"``. Can be overridden on a per-request basis by
+using the ``set_urlconf`` method in ``django.core.urlresolvers``. See
+:ref:`how-django-processes-a-request` for details.
 
 .. setting:: SECRET_KEY
 
