Greatly improved the 404 error message when DEBUG=True. If none of the urlpatterns matches, Django now displays a list of all the urlpatterns it tried. This should catch a lot of newbie errors, and it's helpful even for power users.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@414 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
c517960984
commit
59c3ebc6dd
|
@ -60,9 +60,9 @@ class BaseHandler:
|
||||||
if response:
|
if response:
|
||||||
return response
|
return response
|
||||||
return callback(request, **param_dict)
|
return callback(request, **param_dict)
|
||||||
except exceptions.Http404:
|
except exceptions.Http404, e:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
return self.get_technical_error_response(is404=True)
|
return self.get_technical_error_response(is404=True, exception=e)
|
||||||
else:
|
else:
|
||||||
callback, param_dict = resolver.resolve404()
|
callback, param_dict = resolver.resolve404()
|
||||||
return callback(request, **param_dict)
|
return callback(request, **param_dict)
|
||||||
|
@ -99,14 +99,35 @@ class BaseHandler:
|
||||||
callback, param_dict = resolver.resolve500()
|
callback, param_dict = resolver.resolve500()
|
||||||
return callback(request, **param_dict)
|
return callback(request, **param_dict)
|
||||||
|
|
||||||
def get_technical_error_response(self, is404=False):
|
def get_technical_error_response(self, is404=False, exception=None):
|
||||||
"""
|
"""
|
||||||
Returns an HttpResponse that displays a TECHNICAL error message for a
|
Returns an HttpResponse that displays a TECHNICAL error message for a
|
||||||
fundamental database or coding error.
|
fundamental database or coding error.
|
||||||
"""
|
"""
|
||||||
error_string = "There's been an error:\n\n%s" % self._get_traceback()
|
if is404:
|
||||||
responseClass = is404 and httpwrappers.HttpResponseNotFound or httpwrappers.HttpResponseServerError
|
from django.conf.settings import ROOT_URLCONF
|
||||||
return responseClass(error_string, mimetype='text/plain')
|
from django.utils.html import escape
|
||||||
|
html = ['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">']
|
||||||
|
html.append('<html><head><title>Error 404</title>')
|
||||||
|
# Explicitly tell robots not to archive this, in case this slips
|
||||||
|
# onto a production site.
|
||||||
|
html.append('<meta name="robots" content="NONE,NOARCHIVE" />')
|
||||||
|
html.append('</head><body><h1>Error 404</h1>')
|
||||||
|
try:
|
||||||
|
tried = exception.args[0]['tried']
|
||||||
|
except (IndexError, TypeError):
|
||||||
|
if exception.args:
|
||||||
|
html.append('<p>%s</p>' % escape(exception.args[0]))
|
||||||
|
else:
|
||||||
|
html.append('<p>Using the URLconf defined in <code>%s</code>, Django tried these URL patterns, in this order:</p>' % ROOT_URLCONF)
|
||||||
|
html.append('<ul>%s</ul>' % ''.join(['<li><code>%s</code></li>' % escape(t).replace(' ', ' ') for t in tried]))
|
||||||
|
html.append("<p>The current URL, <code><strong>%r</strong></code>, didn't match any of these.</p>" % exception.args[0]['path'])
|
||||||
|
html.append("<hr /><p>You're seeing this error because you have <code>DEBUG = True</code> in your Django settings file. Change that to <code>False</code>, and Django will display a standard 404 page.</p>")
|
||||||
|
html.append('</body></html>')
|
||||||
|
return httpwrappers.HttpResponseNotFound('\n'.join(html))
|
||||||
|
else:
|
||||||
|
output = "There's been an error:\n\n%s" % self._get_traceback()
|
||||||
|
return httpwrappers.HttpResponseServerError(output, mimetype='text/plain')
|
||||||
|
|
||||||
def _get_traceback(self):
|
def _get_traceback(self):
|
||||||
"Helper function to return the traceback as a string"
|
"Helper function to return the traceback as a string"
|
||||||
|
|
|
@ -10,6 +10,9 @@ a string) and returns a tuple in this format:
|
||||||
from django.core.exceptions import Http404, ViewDoesNotExist
|
from django.core.exceptions import Http404, ViewDoesNotExist
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
class Resolver404(Http404):
|
||||||
|
pass
|
||||||
|
|
||||||
def get_mod_func(callback):
|
def get_mod_func(callback):
|
||||||
# Converts 'django.views.news.stories.story_detail' to
|
# Converts 'django.views.news.stories.story_detail' to
|
||||||
# ['django.views.news.stories', 'story_detail']
|
# ['django.views.news.stories', 'story_detail']
|
||||||
|
@ -52,15 +55,20 @@ class RegexURLResolver:
|
||||||
self.urlconf_name = urlconf_name
|
self.urlconf_name = urlconf_name
|
||||||
|
|
||||||
def resolve(self, path):
|
def resolve(self, path):
|
||||||
|
tried = []
|
||||||
match = self.regex.search(path)
|
match = self.regex.search(path)
|
||||||
if match:
|
if match:
|
||||||
new_path = path[match.end():]
|
new_path = path[match.end():]
|
||||||
for pattern in self.url_patterns:
|
for pattern in self.url_patterns:
|
||||||
|
try:
|
||||||
sub_match = pattern.resolve(new_path)
|
sub_match = pattern.resolve(new_path)
|
||||||
|
except Resolver404, e:
|
||||||
|
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
|
||||||
|
else:
|
||||||
if sub_match:
|
if sub_match:
|
||||||
return sub_match
|
return sub_match
|
||||||
# None of the regexes matched, so raise a 404.
|
tried.append(pattern.regex.pattern)
|
||||||
raise Http404, "Tried all URL patterns but didn't find a match for %r" % path
|
raise Resolver404, {'tried': tried, 'path': new_path}
|
||||||
|
|
||||||
def _get_urlconf_module(self):
|
def _get_urlconf_module(self):
|
||||||
self.urlconf_module = __import__(self.urlconf_name, '', '', [''])
|
self.urlconf_module = __import__(self.urlconf_name, '', '', [''])
|
||||||
|
|
Loading…
Reference in New Issue