diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index ba6e8f0be7..23572465cf 100644 --- a/django/core/handlers/base.py +++ b/django/core/handlers/base.py @@ -95,14 +95,15 @@ class BaseHandler(object): break if response is None: - if hasattr(request, "urlconf"): + if hasattr(request, 'urlconf'): # Reset url resolver with a custom urlconf. urlconf = request.urlconf urlresolvers.set_urlconf(urlconf) resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) - callback, callback_args, callback_kwargs = resolver.resolve( - request.path_info) + resolver_match = resolver.resolve(request.path_info) + callback, callback_args, callback_kwargs = resolver_match + request.resolver_match = resolver_match # Apply view middleware for middleware_method in self._view_middleware: diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index cc2a351d8e..ff929014c0 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -190,6 +190,17 @@ All attributes should be considered read-only, unless stated otherwise below. URLconf for the current request, overriding the :setting:`ROOT_URLCONF` setting. See :ref:`how-django-processes-a-request` for details. +.. attribute:: HttpRequest.resolver_match + + .. versionadded:: 1.5 + + An instance of :class:`~django.core.urlresolvers.ResolverMatch` representing + the resolved url. This attribute is only set after url resolving took place, + which means it's available in all views but not in middleware methods which + are executed before url resolving takes place (like ``process_request``, you + can use ``process_view`` instead). + + Methods ------- diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt index b769debb0b..c25858b5a6 100644 --- a/docs/releases/1.5.txt +++ b/docs/releases/1.5.txt @@ -161,7 +161,7 @@ Django 1.5 also includes several smaller improvements worth noting: :func:`~django.contrib.auth.decorators.login_required` documentation. * Django now provides a mod_wsgi :doc:`auth handler - ` + `. * The :meth:`QuerySet.delete() ` and :meth:`Model.delete() ` can now take @@ -169,6 +169,9 @@ Django 1.5 also includes several smaller improvements worth noting: objects fetched into memory. See :meth:`QuerySet.delete() ` for details. +* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on + the request as ``resolver_match``. + Backwards incompatible changes in 1.5 ===================================== diff --git a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py index fa892a4346..ab2e77af24 100644 --- a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py +++ b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py @@ -28,6 +28,7 @@ otherobj2 = URLObject('nodefault', 'other-ns2') urlpatterns = patterns('regressiontests.urlpatterns_reverse.views', url(r'^normal/$', 'empty_view', name='normal-view'), url(r'^normal/(?P\d+)/(?P\d+)/$', 'empty_view', name='normal-view'), + url(r'^resolver_match/$', 'pass_resolver_match_view', name='test-resolver-match'), url(r'^\+\\\$\*/$', 'empty_view', name='special-view'), diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py index 0ea5ffe380..234897d267 100644 --- a/tests/regressiontests/urlpatterns_reverse/tests.py +++ b/tests/regressiontests/urlpatterns_reverse/tests.py @@ -512,6 +512,11 @@ class ResolverMatchTests(TestCase): self.assertEqual(match[1], args) self.assertEqual(match[2], kwargs) + def test_resolver_match_on_request(self): + response = self.client.get('/resolver_match/') + resolver_match = response.resolver_match + self.assertEqual(resolver_match.url_name, 'test-resolver-match') + class ErroneousViewTests(TestCase): urls = 'regressiontests.urlpatterns_reverse.erroneous_urls' diff --git a/tests/regressiontests/urlpatterns_reverse/views.py b/tests/regressiontests/urlpatterns_reverse/views.py index f631acf3ec..88d169a118 100644 --- a/tests/regressiontests/urlpatterns_reverse/views.py +++ b/tests/regressiontests/urlpatterns_reverse/views.py @@ -19,6 +19,11 @@ def defaults_view(request, arg1, arg2): def erroneous_view(request): import non_existent +def pass_resolver_match_view(request, *args, **kwargs): + response = HttpResponse('') + response.resolver_match = request.resolver_match + return response + uncallable = "Can I be a view? Pleeeease?" class ViewClass(object):