Search code examples
djangodjango-testing

Why does assertRedirects() expect a string rather than a URL?


Why does these two asserts work:

from django.test import TestCase

class MyTests(TestCase):
    def test_1(self):
        response = self.client.get(reverse_lazy('create_cm')) 
        self.assertRedirects(response, reverse('upload_booth'))
        self.assertRedirects(response, str(reverse_lazy('upload_booth')))

but this doesn't:

self.assertRedirects(response, reverse_lazy('upload_booth'))

instead producing this error message:

File "/usr/local/lib/python2.7/dist-packages/django/test/testcases.py", line 300, in assertRedirects e_query, e_fragment))
File "/usr/lib/python2.7/urlparse.py", line 234, in urlunsplit url = '//' + (netloc or '') + url TypeError: coercing to Unicode: need string or buffer, proxy found

What exactly is the difference in return values from reverse and reverse_lazy, and why are they different?


Solution

  • The implementations of lazy functions do not return the value directly on instantiation, instead return a proxy object. As a specific call to this object happens its real value gets evaluated and returned.

    In case of reverse_lazy you can see this in your own example:

    str(reverse_lazy('upload_booth'))
    

    This is a call to the proxy object's __str__ method and then really returns a string instead of a proxy object.

    All implementation details can be found at the Django docs.