0

I am in Django HTTP error codes hell. Would be great if an expert can help me out of my misconfiguration.

My Django project runs with nginx as a reverse proxy coupled to a gunicorn application server.

Requirement:

I want a custom Page not found template to render (i.e. 404) when a url pattern is entered that doesn't exist in my urls.py. Sounds simple enough, and is well documented.

I have already gone ahead and implemented this.

The Problem:

Assume example.com is my live project.

1) If I try to access https://example.com/asdfasdf (i.e. unmatched, random gibberish) on my production server, it displays the 500 template instead of 404.

2) Next, if I try to curl the said url pattern via curl -I https://example.com/asdfasdf/, I see 200 OK instead of 404 or 500. Wth?

3) Moreover, if I try the same behavior with Debug = True on localhost, 404 is returned correctly (both template and HTTP error code are in consonance).

These 3 behaviors are quite perplexing.

My configuration:

I created error_views.py and inserted it in the folder where I keep my regular views.py. This error file contains:

from django.shortcuts import render

def server_error(request):
    return render(request, '500.html')

def not_found(request):
    return render(request, '404.html')

def permission_denied(request):
    return render(request, '404.html')

def bad_request(request):
    return render(request, '404.html')

In my urls.py (kept in the same folder as settings.py), I added the following after all url patterns:

handler404 = 'my_app.error_views.not_found'
handler500 = 'my_app.error_views.server_error'
handler403 = 'my_app.error_views.permission_denied'
handler400 = 'my_app.error_views.bad_request'

I created 404.html and 500.html, and inserted them in the default /templates/ directory.

In settings.py, I have ALLOWED_HOSTS = ['*']

Lastly, my nginx conf dealing with this is as follows (placed within the server block in the virtual host file):

# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
    root /home/ubuntu/this_proj/project_dir/templates/;
}

location = /too_bad.svg {
    root /home/ubuntu/this_proj/project_dir/static/img/;
}

All of this is fairly regular stuff and I'm missing what I've misconfigured here. Can an expert guide me out of this mess?

Thanks in advance, and please ask for more information in case warranted.

Note: I tried solutions provided in similar questions on SO here and here. Needless to say, those misconfigurations were very different, displaying none of the symptoms I'm seeing.

Hassan Baig
  • 15,055
  • 27
  • 102
  • 205

1 Answers1

1

If you use a custom handler, you have to explicitly set the proper http status for the response object. If you don't set the status, the default is 200 OK.

def not_found(request):
    return render(request, '404.html', status=404)
Håken Lid
  • 22,318
  • 9
  • 52
  • 67