From 29c1151a5577cccfdb18109ccb42330cde124d89 Mon Sep 17 00:00:00 2001 From: Julia Matsieva Date: Mon, 16 Jun 2014 00:39:18 -0700 Subject: [PATCH] Fixed #22756 -- Added view name to technical 404 template if Http404 is raised. Thanks Keryn Knight for the suggestion. --- AUTHORS | 1 + django/views/debug.py | 27 ++++++++++++++++++++++++++- tests/view_tests/tests/test_debug.py | 11 +++++++++++ tests/view_tests/urls.py | 3 +++ tests/view_tests/views.py | 13 ++++++++++++- 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 13b6bdee5e..2fb754b543 100644 --- a/AUTHORS +++ b/AUTHORS @@ -430,6 +430,7 @@ answer newbie questions, and generally made Django that much better: Orestis Markou Andrés Torres Marroquín Pablo Martín + Julia Matsieva Takashi Matsuo Zlatko Mašek Yasushi Masuda diff --git a/django/views/debug.py b/django/views/debug.py index 2997f2da7c..ac81ecaf9e 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -7,6 +7,7 @@ import sys import types from django.conf import settings +from django.core.urlresolvers import resolve, Resolver404 from django.http import (HttpResponse, HttpResponseNotFound, HttpRequest, build_request_repr) from django.template import Template, Context, TemplateDoesNotExist @@ -496,6 +497,23 @@ def technical_404_response(request, exception): if isinstance(urlconf, types.ModuleType): urlconf = urlconf.__name__ + caller = '' + try: + resolver_match = resolve(request.path) + except Resolver404: + pass + else: + obj = resolver_match.func + + if hasattr(obj, '__name__'): + caller = obj.__name__ + elif hasattr(obj, '__class__') and hasattr(obj.__class__, '__name__'): + caller = obj.__class__.__name__ + + if hasattr(obj, '__module__'): + module = obj.__module__ + caller = '%s.%s' % (module, caller) + t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') c = Context({ 'urlconf': urlconf, @@ -505,6 +523,7 @@ def technical_404_response(request, exception): 'reason': force_bytes(exception, errors='replace'), 'request': request, 'settings': get_safe_settings(), + 'raising_view_name': caller, }) return HttpResponseNotFound(t.render(c), content_type='text/html') @@ -1091,8 +1110,14 @@ TECHNICAL_404_TEMPLATE = """ Request URL: - {{ request.build_absolute_uri|escape }} + {{ request.build_absolute_uri|escape }} + {% if raising_view_name %} + + Raised by: + {{ raising_view_name }} + + {% endif %}
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index 32a8304dca..7d800ae591 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -72,8 +72,19 @@ class DebugViewTests(TestCase): def test_404_not_in_urls(self): response = self.client.get('/not-in-urls') + self.assertNotContains(response, "Raised by:", status_code=404) self.assertContains(response, "not-in-urls, didn't match", status_code=404) + def test_technical_404(self): + response = self.client.get('/views/technical404/') + self.assertContains(response, "Raised by:", status_code=404) + self.assertContains(response, "view_tests.views.technical404", status_code=404) + + def test_classbased_technical_404(self): + response = self.client.get('/views/classbased404/') + self.assertContains(response, "Raised by:", status_code=404) + self.assertContains(response, "view_tests.views.Http404View", status_code=404) + def test_view_exceptions(self): for n in range(len(except_args)): self.assertRaises(BrokenException, self.client.get, diff --git a/tests/view_tests/urls.py b/tests/view_tests/urls.py index fdb263fa71..202f8589eb 100644 --- a/tests/view_tests/urls.py +++ b/tests/view_tests/urls.py @@ -57,6 +57,9 @@ urlpatterns = [ url(r'raises404/$', views.raises404), url(r'raises500/$', views.raises500), + url(r'technical404/$', views.technical404, name="my404"), + url(r'classbased404/$', views.Http404View.as_view()), + # i18n views url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^jsi18n/$', i18n.javascript_catalog, js_info_dict), diff --git a/tests/view_tests/views.py b/tests/view_tests/views.py index 2e8a270e94..003ea76b1f 100644 --- a/tests/view_tests/views.py +++ b/tests/view_tests/views.py @@ -7,7 +7,7 @@ import sys from django.core.exceptions import PermissionDenied, SuspiciousOperation from django.core.urlresolvers import get_resolver -from django.http import HttpResponse, HttpResponseRedirect, JsonResponse +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, Http404 from django.shortcuts import render_to_response, render from django.template import Context, RequestContext, TemplateDoesNotExist from django.views.debug import technical_500_response, SafeExceptionReporterFilter @@ -16,6 +16,8 @@ from django.views.decorators.debug import (sensitive_post_parameters, from django.utils._os import upath from django.utils.log import getLogger +from django.views.generic import View + from . import BrokenException, except_args dirs = (os.path.join(os.path.dirname(upath(__file__)), 'other_templates'),) @@ -60,6 +62,15 @@ def raises404(request): resolver.resolve('/not-in-urls') +def technical404(request): + raise Http404("Testing technical 404.") + + +class Http404View(View): + def get(self, request): + raise Http404("Testing class-based technical 404.") + + def redirect(request): """ Forces an HTTP redirect.