Skip to content
Browse files

Fixed #5925 -- Added new lazily evaluated version of django.core.urlr…

…esolvers.reverse. Thanks, SmileyChris, Preston Timmons and Julien Phalip.

git-svn-id: bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent f459169 commit 79afd552788400bbcb8d399df1336ec7100eabd9 @jezdez jezdez committed
4 django/core/
@@ -15,7 +15,7 @@
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
-from django.utils.functional import memoize
+from django.utils.functional import memoize, lazy
from django.utils.importlib import import_module
from django.utils.regex_helper import normalize
@@ -390,6 +390,8 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current
return iri_to_uri(u'%s%s' % (prefix, resolver.reverse(view,
*args, **kwargs)))
+reverse_lazy = lazy(reverse, str)
def clear_url_caches():
global _resolver_cache
global _callable_cache
6 docs/releases/1.4.txt
@@ -37,6 +37,12 @@ compatibility with old browsers, this change means that you can use any HTML5
features you need in admin pages without having to lose HTML validity or
override the provided templates to change the doctype.
+A lazily evaluated version of :func:`django.core.urlresolvers.reverse` was
+added to allow using URL reversals before the project's URLConf gets loaded.
.. _backwards-incompatible-changes-1.4:
Backwards incompatible changes in 1.4
20 docs/topics/http/urls.txt
@@ -827,6 +827,26 @@ namespaces into URLs on specific application instances, according to the
``urllib.quote``) to the ouput of :meth:`~django.core.urlresolvers.reverse`
may produce undesirable results.
+.. versionadded:: 1.4
+A lazily evaluated version of `reverse()`_.
+It is useful for when you need to use a URL reversal before your project's
+URLConf is loaded. Some common cases where this method is necessary are::
+* providing a reversed URL as the ``url`` attribute of a generic class-based
+ view.
+* providing a reversed URL to a decorator (such as the ``login_url`` argument
+ for the :func:`django.contrib.auth.decorators.permission_required`
+ decorator).
+* providing a reversed URL as a default value for a parameter in a function's
+ signature.
16 tests/regressiontests/urlpatterns_reverse/
@@ -10,6 +10,7 @@
from django.shortcuts import redirect
from django.test import TestCase
from django.utils import unittest
+from django.contrib.auth.models import User
import urlconf_outer
import urlconf_inner
@@ -218,6 +219,21 @@ def test_404_tried_urls_have_names(self):
self.assertEqual(, e['name'], 'Wrong URL name. Expected "%s", got "%s".' % (e['name'],
+class ReverseLazyTest(TestCase):
+ urls = 'regressiontests.urlpatterns_reverse.reverse_lazy_urls'
+ def test_redirect_with_lazy_reverse(self):
+ response = self.client.get('/redirect/')
+ self.assertRedirects(response, "/redirected_to/", status_code=301)
+ def test_user_permission_with_lazy_reverse(self):
+ user = User.objects.create_user('alfred', '', password='testpw')
+ response = self.client.get('/login_required_view/')
+ self.assertRedirects(response, "/login/?next=/login_required_view/", status_code=302)
+ self.client.login(username='alfred', password='testpw')
+ response = self.client.get('/login_required_view/')
+ self.assertEqual(response.status_code, 200)
class ReverseShortcutTests(TestCase):
urls = 'regressiontests.urlpatterns_reverse.urls'
11 tests/regressiontests/urlpatterns_reverse/
@@ -1,4 +1,8 @@
from django.http import HttpResponse
+from django.views.generic import RedirectView
+from django.core.urlresolvers import reverse_lazy
+from django.contrib.auth.decorators import user_passes_test
def empty_view(request, *args, **kwargs):
return HttpResponse('')
@@ -15,5 +19,12 @@ def __call__(self, request, *args, **kwargs):
view_class_instance = ViewClass()
+class LazyRedictView(RedirectView):
+ url = reverse_lazy('named-lazy-url-redirected-to')
+@user_passes_test(lambda u: u.is_authenticated(), login_url=reverse_lazy('some-login-page'))
+def login_required_view(request):
+ return HttpResponse('Hello you')
def bad_view(request, *args, **kwargs):
raise ValueError("I don't think I'm getting good value for this view")

0 comments on commit 79afd55

Please sign in to comment.
Something went wrong with that request. Please try again.