diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py
index 115b6ad56f..356e9c45a9 100644
--- a/django/core/handlers/base.py
+++ b/django/core/handlers/base.py
@@ -60,9 +60,9 @@ class BaseHandler:
if response:
return response
return callback(request, **param_dict)
- except exceptions.Http404:
+ except exceptions.Http404, e:
if DEBUG:
- return self.get_technical_error_response(is404=True)
+ return self.get_technical_error_response(is404=True, exception=e)
else:
callback, param_dict = resolver.resolve404()
return callback(request, **param_dict)
@@ -99,14 +99,35 @@ class BaseHandler:
callback, param_dict = resolver.resolve500()
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
fundamental database or coding error.
"""
- error_string = "There's been an error:\n\n%s" % self._get_traceback()
- responseClass = is404 and httpwrappers.HttpResponseNotFound or httpwrappers.HttpResponseServerError
- return responseClass(error_string, mimetype='text/plain')
+ if is404:
+ from django.conf.settings import ROOT_URLCONF
+ from django.utils.html import escape
+ html = ['']
+ html.append('
Error 404')
+ # Explicitly tell robots not to archive this, in case this slips
+ # onto a production site.
+ html.append('')
+ html.append('Error 404
')
+ try:
+ tried = exception.args[0]['tried']
+ except (IndexError, TypeError):
+ if exception.args:
+ html.append('%s
' % escape(exception.args[0]))
+ else:
+ html.append('Using the URLconf defined in %s
, Django tried these URL patterns, in this order:
' % ROOT_URLCONF)
+ html.append('' % ''.join(['%s
' % escape(t).replace(' ', ' ') for t in tried]))
+ html.append("The current URL, %r
, didn't match any of these.
" % exception.args[0]['path'])
+ html.append("
You're seeing this error because you have DEBUG = True
in your Django settings file. Change that to False
, and Django will display a standard 404 page.
")
+ html.append('')
+ 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):
"Helper function to return the traceback as a string"
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index 50f9336171..178c2d139a 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -10,6 +10,9 @@ a string) and returns a tuple in this format:
from django.core.exceptions import Http404, ViewDoesNotExist
import re
+class Resolver404(Http404):
+ pass
+
def get_mod_func(callback):
# Converts 'django.views.news.stories.story_detail' to
# ['django.views.news.stories', 'story_detail']
@@ -52,15 +55,20 @@ class RegexURLResolver:
self.urlconf_name = urlconf_name
def resolve(self, path):
+ tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
- sub_match = pattern.resolve(new_path)
- if sub_match:
- return sub_match
- # None of the regexes matched, so raise a 404.
- raise Http404, "Tried all URL patterns but didn't find a match for %r" % path
+ try:
+ 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:
+ return sub_match
+ tried.append(pattern.regex.pattern)
+ raise Resolver404, {'tried': tried, 'path': new_path}
def _get_urlconf_module(self):
self.urlconf_module = __import__(self.urlconf_name, '', '', [''])