Ticket #5034: set_urlconf.2.diff

File set_urlconf.2.diff, 8.1 KB (added by seanbrant, 6 years ago)

Updated to work with 1.2 also clears _urlconfs dict on each request

  • django/core/urlresolvers.py

     
    3232# be empty.
    3333_prefixes = {}
    3434
     35# Overridden URLconfs for each thread are stored here.
     36_urlconfs = {}
     37
    3538class Resolver404(Http404):
    3639    pass
    3740
     
    300303                "arguments '%s' not found." % (lookup_view_s, args, kwargs))
    301304
    302305def resolve(path, urlconf=None):
     306    if urlconf is None:
     307        urlconf = get_urlconf()
    303308    return get_resolver(urlconf).resolve(path)
    304309
    305310def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
     311    if urlconf is None:
     312            urlconf = get_urlconf()
    306313    resolver = get_resolver(urlconf)
    307314    args = args or []
    308315    kwargs = kwargs or {}
     
    371378    """
    372379    return _prefixes.get(currentThread(), u'/')
    373380
     381def set_urlconf(urlconf_name):
     382    """
     383    Sets the URLconf for the current thread (overriding the default one in
     384    settings). Set to None to revert back to the default.
     385    """
     386    thread = currentThread()
     387    if urlconf_name:
     388        _urlconfs[thread] = urlconf_name
     389    else:
     390        # This is a lot faster than wrapping in a try/except.
     391        if thread in _urlconfs:
     392            del _urlconfs[thread]
     393
     394def get_urlconf(default=None):
     395    """
     396    Returns the root URLconf to use for the current thread if it has been
     397    changed from the default one.
     398    """
     399    thread = currentThread()
     400    # It's faster to check first than to do _urlconfs.get(thread)
     401    if thread in _urlconfs:
     402        return _urlconfs[thread]
     403    return default
     404 No newline at end of file
  • django/core/handlers/base.py

     
    6767        "Returns an HttpResponse object for the given HttpRequest"
    6868        from django.core import exceptions, urlresolvers
    6969        from django.conf import settings
    70 
     70       
     71        # Reset the urlconf for this thread.
     72        urlresolvers.set_urlconf(None)
     73       
    7174        # Apply request middleware
    7275        for middleware_method in self._request_middleware:
    7376            response = middleware_method(request)
    7477            if response:
    7578                return response
    7679
    77         # Get urlconf from request object, if available.  Otherwise use default.
    78         urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
     80        # Get overridden urlconf for this thread, if available. Otherwise use
     81        # default.
     82        urlconf = urlresolvers.get_urlconf()
     83        if urlconf is None:
     84            # Get urlconf from request object, if available (deprecated).
     85            if hasattr(request, 'urlconf'):
     86                import warnings
     87                warnings.warn("The 'request.urlconf' attribute is deprecated. "
     88                              "Use the 'django.core.urlresolvers::set_urlconf'"
     89                              " method instead.", DeprecationWarning)
     90                urlconf = request.urlconf
     91                urlresolvers.set_urlconf(urlconf)
     92            else:
     93                urlconf = settings.ROOT_URLCONF
    7994
    8095        resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
    8196        try:
     
    132147            exc_info = sys.exc_info()
    133148            receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
    134149            return self.handle_uncaught_exception(request, resolver, exc_info)
     150        finally:
     151            # Reset the urlconf for this thread.
     152            urlresolvers.set_urlconf(None)
    135153
    136154    def handle_uncaught_exception(self, request, resolver, exc_info):
    137155        """
  • tests/regressiontests/urlpatterns_reverse/tests.py

     
    1414ImproperlyConfigured: The included urlconf regressiontests.urlpatterns_reverse.no_urls doesn't have any patterns in it
    1515"""}
    1616
     17import re
    1718import unittest
    1819
     20from django.conf import settings
    1921from django.core.urlresolvers import reverse, resolve, NoReverseMatch, Resolver404
    2022from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
    2123from django.shortcuts import redirect
    2224from django.test import TestCase
    2325
     26import urlconf_outer
     27import urlconf_inner
     28import middleware
     29
    2430test_data = (
    2531    ('places', '/places/3/', [3], {}),
    2632    ('places', '/places/3/', ['3'], {}),
     
    239245        self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], current_app='other-ns1'))
    240246        self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1'))
    241247
     248
     249class SetUrlConf(TestCase):
     250    def setUp(self):
     251        self.root_urlconf = settings.ROOT_URLCONF
     252        self.middleware_classes = settings.MIDDLEWARE_CLASSES
     253        settings.ROOT_URLCONF = urlconf_outer.__name__
     254       
     255    def tearDown(self):
     256        settings.ROOT_URLCONF = self.root_urlconf
     257        settings.MIDDLEWARE_CLASSES = self.middleware_classes
     258       
     259    def test_handler(self):
     260        response = self.client.get('/test/me/')
     261        self.assertEqual(response.status_code, 200)
     262        self.assertEqual(response.content, 'outer:/test/me/,'
     263                                           'inner:/inner_urlconf/second_test/')
     264        response = self.client.get('/inner_urlconf/second_test/')
     265        self.assertEqual(response.status_code, 200)
     266        response = self.client.get('/second_test/')
     267        self.assertEqual(response.status_code, 404)
     268       
     269    def test_handler_overridden(self):
     270        settings.MIDDLEWARE_CLASSES += (
     271            '%s.ChangeUrlconfMiddleware' % middleware.__name__,
     272        )
     273        response = self.client.get('/test/me/')
     274        self.assertEqual(response.status_code, 404)
     275        response = self.client.get('/inner_urlconf/second_test/')
     276        self.assertEqual(response.status_code, 404)
     277        response = self.client.get('/second_test/')
     278        self.assertEqual(response.status_code, 200)
     279        self.assertEqual(response.content, 'outer:,inner:/second_test/')
     280 No newline at end of file
  • docs/topics/http/urls.txt

     
    3939algorithm the system follows to determine which Python code to execute:
    4040
    4141    1. Django determines the root URLconf module to use. Ordinarily,
    42        this is the value of the ``ROOT_URLCONF`` setting, but if the incoming
    43        ``HttpRequest`` object has an attribute called ``urlconf``, its value
    44        will be used in place of the ``ROOT_URLCONF`` setting.
     42       this is the value of the ``ROOT_URLCONF`` setting, this can be overridden
     43       per request by calling the ``set_urlconf`` method found in
     44       ``django.core.urlresolvers`` (passing in the value to be used in place of
     45       the ``ROOT_URLCONF`` setting).
    4546
    4647    2. Django loads that Python module and looks for the variable
    4748       ``urlpatterns``. This should be a Python list, in the format returned by
  • docs/ref/settings.txt

     
    804804
    805805Default: Not defined
    806806
    807 A string representing the full Python import path to your root URLconf. For example:
    808 ``"mydjangoapps.urls"``. Can be overridden on a per-request basis by
    809 setting the attribute ``urlconf`` on the incoming ``HttpRequest``
    810 object. See :ref:`how-django-processes-a-request` for details.
     807A string representing the full Python import path to your root URLconf. For
     808example: ``"mydjangoapps.urls"``. Can be overridden on a per-request basis by
     809using the ``set_urlconf`` method in ``django.core.urlresolvers``. See
     810:ref:`how-django-processes-a-request` for details.
    811811
    812812.. setting:: SECRET_KEY
    813813
Back to Top