Trouble testing POST request with follow=True

I’m looking to test for a 303 See Other status code when a User attempts to login. Django does not have a built in class to handle this status code, so I constructed a sub class of HttpResponse .

from http import HTTPStatus

from django.http import HttpResponse

class HttpResponseSeeOther(HttpResponse):
    '''Represents a 303 status code'''
    status_code = HTTPStatus.SEE_OTHER    

Next, I constructed a TestCase to test a View’s response when it is passed valid form data. However, the test raises this error: AttributeError: 'HttpResponseSeeOther' object has no attribute 'url' . Going over the Django docs, I cannot see any reference to a Response object having an URL attribute.

How can I go about addressing this error so that a server returns a 200 OK response after a successful 303 See Other redirect?

test_views.py

class TestUserLoginPage(TestCase):

@classmethod
def setUpTestData(cls):
    User.objects.create_user(username="User", password="password")
    cls.login_creds = {
        'username': 'User',
        'password': 'password'
    }

    cls.invalid_login_creds = {
        'username': "User2",
        'password': 'password2'
    }

def test_successful_login_redirect(self):
    response = self.client.post(
        reverse("login"),
        data=self.login_creds,
        follow=True
    )
    self.assertRedirects(response, reverse("photos:main_gallery"), status_code=303)
    self.assertTemplateUsed(response, "photos/main_gallery.html")

views.py

class LoginPage(View):
    def get(self, request):
        form = UserAuthenticationForm()
        return render(request, 'login.html', context={'form': form})

    def post(self, request):
        form = UserAuthenticationForm(request, request.POST)
        if form.is_valid():
            messages.success(request, f"Welcome {request.user}!")
            return HttpResponseSeeOther(reverse("photos:main_gallery"))
        messages.info(request, "Login Failed. Username not registered.")
        form = UserAuthenticationForm()
        return render(request, "login.html", context={'form': form})

Traceback:

ERROR: test_successful_login_redirect (photo_app.tests.test_views.TestUserLoginPage)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\photo_project\django_photo_app\photo_app\tests\test_views.py", line 34, in test_successful_login_redirect
    follow=True
  File "C:\photo_project\venv\lib\site-packages\django\test\client.py", line 545, in post
    response = self._handle_redirects(response, data=data, content_type=content_type, **extra)
  File "C:\photo_project\venv\lib\site-packages\django\test\client.py", line 686, in _handle_redirects
    response_url = response.url
AttributeError: 'HttpResponseSeeOther' object has no attribute 'url'

Hey!

I don’t think the HttpResponse class understands that you are passing an argument, and it should be an url attribute: https://github.com/django/django/blob/master/django/http/response.py#L329

I would suggest using the HttpResponseRedirectBase (https://github.com/django/django/blob/master/django/http/response.py#L494) as your base class, and then you’ll be able to tell the browser to redirect, as you would do with HttpResponseRedirect (https://github.com/django/django/blob/master/django/http/response.py#L515).

from http import HTTPStatus

from django.http.response import HttpResponseRedirectBase

class HttpResponseSeeOther(HttpResponseRedirectBase):
    '''Represents a 303 status code'''
    status_code = HTTPStatus.SEE_OTHER 

I hope it helps :slight_smile: