I'm writing Django tests for a live Heroku server, and am having trouble getting Django to recognize a POST request through a redirect.
On my test server, things work fine:
views.py
def detect_post(request):
"""
Detect whether this is a POST or a GET request.
"""
if request.method == 'POST':
return HttpResponse(
json.dumps({"POST request": "POST request detected"}),
content_type="application/json"
)
# If this is a GET request, return an error
else:
return HttpResponse(
json.dumps({"Access denied": "You are not permitted to access this page."}),
content_type="application/json"
)
python manage.py shell
>>> from django.urls import reverse
>>> from django.test import Client
>>> c = Client()
# GET request returns an error, as expected:
>>> response = c.get(reverse('detectpost'), follow=True)
>>> response.status_code
200
>>> response.content
b'{"Access denied": "You are not permitted to access this page."}'
# POST request returns success, as expected
>>> response = c.post(reverse('detectpost'))
>>> response.status_code
200
>>> response.content
b'{"POST request": "POST request detected"}'
However, when I move over to my production server, I encounter problems. I think it's because my production server has SECURE_SSL_REDIRECT
, so all pages are redirecting to an SSL-enabled version of the same page. Here's what happens when I try to run the same test code on my production server:
heroku run python manage.py shell
>>> from django.urls import reverse
>>> from django.test import Client
>>> c = Client()
# GET request returns an error, as expected:
>>> response = c.get(reverse('detectpost'), follow=True)
>>> response.status_code
200
>>> response.content
b'{"Access denied": "You are not permitted to access this page."}'
# POST request, however, has problems
>>> response = c.post(reverse('detectpost'), follow=True)
>>> response.status_code
200
>>> response.content
b'{"Access denied": "You are not permitted to access this page."}'
>>> response.redirect_chain
[('https://testserver/testpost/', 301)]
# I believe that the POST request isn't being detected because my site uses redirects
>>> response = c.post(reverse('detectpost'))
>>> response.status_code
301
How can I get my Django TestClient to register a POST request even through a redirect? I expected the follow=True
flag to accomplish this, but it doesn't seem to be working.
When you use client.post
, you can simulate a request to the https
URL by setting secure=True
.
response = c.post(reverse('detectpost'), follow=True, secure=True)
When the Django secure middleware returns a 301 redirect from http
to https
, browsers will make a GET request to the new URL even if the original request was a POST request.
There is a 307 response which tells the browser not to change the method. However I would not try to get Django to return a 307. Just change the client.post()
call to use secure=True
as I suggested above.