Loading django/views/defaults.py +21 −4 Original line number Diff line number Diff line Loading @@ -4,12 +4,17 @@ from django.utils import six from django.utils.encoding import force_text from django.views.decorators.csrf import requires_csrf_token ERROR_404_TEMPLATE_NAME = '404.html' ERROR_403_TEMPLATE_NAME = '403.html' ERROR_400_TEMPLATE_NAME = '400.html' ERROR_500_TEMPLATE_NAME = '500.html' # This can be called when CsrfViewMiddleware.process_view has not run, # therefore need @requires_csrf_token in case the template needs # {% csrf_token %}. @requires_csrf_token def page_not_found(request, exception, template_name='404.html'): def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME): """ Default 404 handler. Loading Loading @@ -40,6 +45,9 @@ def page_not_found(request, exception, template_name='404.html'): body = template.render(context, request) content_type = None # Django will use DEFAULT_CONTENT_TYPE except TemplateDoesNotExist: if template_name != ERROR_404_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise template = Engine().from_string( '<h1>Not Found</h1>' '<p>The requested URL {{ request_path }} was not found on this server.</p>') Loading @@ -49,7 +57,7 @@ def page_not_found(request, exception, template_name='404.html'): @requires_csrf_token def server_error(request, template_name='500.html'): def server_error(request, template_name=ERROR_500_TEMPLATE_NAME): """ 500 error handler. Loading @@ -59,12 +67,15 @@ def server_error(request, template_name='500.html'): try: template = loader.get_template(template_name) except TemplateDoesNotExist: if template_name != ERROR_500_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise return http.HttpResponseServerError('<h1>Server Error (500)</h1>', content_type='text/html') return http.HttpResponseServerError(template.render()) @requires_csrf_token def bad_request(request, exception, template_name='400.html'): def bad_request(request, exception, template_name=ERROR_400_TEMPLATE_NAME): """ 400 error handler. Loading @@ -74,6 +85,9 @@ def bad_request(request, exception, template_name='400.html'): try: template = loader.get_template(template_name) except TemplateDoesNotExist: if template_name != ERROR_400_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise return http.HttpResponseBadRequest('<h1>Bad Request (400)</h1>', content_type='text/html') # No exception content is passed to the template, to not disclose any sensitive information. return http.HttpResponseBadRequest(template.render()) Loading @@ -83,7 +97,7 @@ def bad_request(request, exception, template_name='400.html'): # therefore need @requires_csrf_token in case the template needs # {% csrf_token %}. @requires_csrf_token def permission_denied(request, exception, template_name='403.html'): def permission_denied(request, exception, template_name=ERROR_403_TEMPLATE_NAME): """ Permission denied (403) handler. Loading @@ -96,6 +110,9 @@ def permission_denied(request, exception, template_name='403.html'): try: template = loader.get_template(template_name) except TemplateDoesNotExist: if template_name != ERROR_403_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise return http.HttpResponseForbidden('<h1>403 Forbidden</h1>', content_type='text/html') return http.HttpResponseForbidden( template.render(request=request, context={'exception': force_text(exception)}) Loading docs/ref/views.txt +16 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,10 @@ Three things to note about 404 views: second parameter, the exception that triggered the error. A useful representation of the exception is also passed in the template context. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``. .. _http_internal_server_error_view: The 500 (server error) view Loading @@ -113,6 +117,10 @@ If :setting:`DEBUG` is set to ``True`` (in your settings module), then your 500 view will never be used, and the traceback will be displayed instead, with some debug information. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``. .. _http_forbidden_view: The 403 (HTTP Forbidden) view Loading Loading @@ -148,6 +156,10 @@ view you can use code like this:: unicode representation of the exception is also passed in the template context. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``. .. _http_bad_request_view: The 400 (bad request) view Loading @@ -173,3 +185,7 @@ filesystem paths. The signature of ``bad_request()`` changed in Django 1.9. The function now accepts a second parameter, the exception that triggered the error. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``. docs/releases/1.10.txt +3 −0 Original line number Diff line number Diff line Loading @@ -464,6 +464,9 @@ Miscellaneous now better to call the ``LogEntry.get_change_message()`` method which will provide the message in the current language. * The default error views now raise ``TemplateDoesNotExist`` if a nonexistent ``template_name`` is specified. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading tests/view_tests/tests/test_defaults.py +26 −1 Original line number Diff line number Diff line Loading @@ -4,8 +4,13 @@ import datetime from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.test import TestCase from django.http import Http404 from django.template import TemplateDoesNotExist from django.test import RequestFactory, TestCase from django.test.utils import override_settings from django.views.defaults import ( bad_request, page_not_found, permission_denied, server_error, ) from ..models import Article, Author, UrlArticle Loading Loading @@ -123,3 +128,23 @@ class DefaultsTests(TestCase): response = self.client.get('/server_error/') self.assertEqual(response['Content-Type'], 'text/html') def test_custom_templates_wrong(self): """ Default error views should raise TemplateDoesNotExist when passed a template that doesn't exist. """ rf = RequestFactory() request = rf.get('/') with self.assertRaises(TemplateDoesNotExist): bad_request(request, Exception(), template_name='nonexistent') with self.assertRaises(TemplateDoesNotExist): permission_denied(request, Exception(), template_name='nonexistent') with self.assertRaises(TemplateDoesNotExist): page_not_found(request, Http404(), template_name='nonexistent') with self.assertRaises(TemplateDoesNotExist): server_error(request, template_name='nonexistent') Loading
django/views/defaults.py +21 −4 Original line number Diff line number Diff line Loading @@ -4,12 +4,17 @@ from django.utils import six from django.utils.encoding import force_text from django.views.decorators.csrf import requires_csrf_token ERROR_404_TEMPLATE_NAME = '404.html' ERROR_403_TEMPLATE_NAME = '403.html' ERROR_400_TEMPLATE_NAME = '400.html' ERROR_500_TEMPLATE_NAME = '500.html' # This can be called when CsrfViewMiddleware.process_view has not run, # therefore need @requires_csrf_token in case the template needs # {% csrf_token %}. @requires_csrf_token def page_not_found(request, exception, template_name='404.html'): def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME): """ Default 404 handler. Loading Loading @@ -40,6 +45,9 @@ def page_not_found(request, exception, template_name='404.html'): body = template.render(context, request) content_type = None # Django will use DEFAULT_CONTENT_TYPE except TemplateDoesNotExist: if template_name != ERROR_404_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise template = Engine().from_string( '<h1>Not Found</h1>' '<p>The requested URL {{ request_path }} was not found on this server.</p>') Loading @@ -49,7 +57,7 @@ def page_not_found(request, exception, template_name='404.html'): @requires_csrf_token def server_error(request, template_name='500.html'): def server_error(request, template_name=ERROR_500_TEMPLATE_NAME): """ 500 error handler. Loading @@ -59,12 +67,15 @@ def server_error(request, template_name='500.html'): try: template = loader.get_template(template_name) except TemplateDoesNotExist: if template_name != ERROR_500_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise return http.HttpResponseServerError('<h1>Server Error (500)</h1>', content_type='text/html') return http.HttpResponseServerError(template.render()) @requires_csrf_token def bad_request(request, exception, template_name='400.html'): def bad_request(request, exception, template_name=ERROR_400_TEMPLATE_NAME): """ 400 error handler. Loading @@ -74,6 +85,9 @@ def bad_request(request, exception, template_name='400.html'): try: template = loader.get_template(template_name) except TemplateDoesNotExist: if template_name != ERROR_400_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise return http.HttpResponseBadRequest('<h1>Bad Request (400)</h1>', content_type='text/html') # No exception content is passed to the template, to not disclose any sensitive information. return http.HttpResponseBadRequest(template.render()) Loading @@ -83,7 +97,7 @@ def bad_request(request, exception, template_name='400.html'): # therefore need @requires_csrf_token in case the template needs # {% csrf_token %}. @requires_csrf_token def permission_denied(request, exception, template_name='403.html'): def permission_denied(request, exception, template_name=ERROR_403_TEMPLATE_NAME): """ Permission denied (403) handler. Loading @@ -96,6 +110,9 @@ def permission_denied(request, exception, template_name='403.html'): try: template = loader.get_template(template_name) except TemplateDoesNotExist: if template_name != ERROR_403_TEMPLATE_NAME: # Reraise if it's a missing custom template. raise return http.HttpResponseForbidden('<h1>403 Forbidden</h1>', content_type='text/html') return http.HttpResponseForbidden( template.render(request=request, context={'exception': force_text(exception)}) Loading
docs/ref/views.txt +16 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,10 @@ Three things to note about 404 views: second parameter, the exception that triggered the error. A useful representation of the exception is also passed in the template context. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``. .. _http_internal_server_error_view: The 500 (server error) view Loading @@ -113,6 +117,10 @@ If :setting:`DEBUG` is set to ``True`` (in your settings module), then your 500 view will never be used, and the traceback will be displayed instead, with some debug information. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``. .. _http_forbidden_view: The 403 (HTTP Forbidden) view Loading Loading @@ -148,6 +156,10 @@ view you can use code like this:: unicode representation of the exception is also passed in the template context. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``. .. _http_bad_request_view: The 400 (bad request) view Loading @@ -173,3 +185,7 @@ filesystem paths. The signature of ``bad_request()`` changed in Django 1.9. The function now accepts a second parameter, the exception that triggered the error. .. versionchanged:: 1.10 Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.
docs/releases/1.10.txt +3 −0 Original line number Diff line number Diff line Loading @@ -464,6 +464,9 @@ Miscellaneous now better to call the ``LogEntry.get_change_message()`` method which will provide the message in the current language. * The default error views now raise ``TemplateDoesNotExist`` if a nonexistent ``template_name`` is specified. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading
tests/view_tests/tests/test_defaults.py +26 −1 Original line number Diff line number Diff line Loading @@ -4,8 +4,13 @@ import datetime from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.test import TestCase from django.http import Http404 from django.template import TemplateDoesNotExist from django.test import RequestFactory, TestCase from django.test.utils import override_settings from django.views.defaults import ( bad_request, page_not_found, permission_denied, server_error, ) from ..models import Article, Author, UrlArticle Loading Loading @@ -123,3 +128,23 @@ class DefaultsTests(TestCase): response = self.client.get('/server_error/') self.assertEqual(response['Content-Type'], 'text/html') def test_custom_templates_wrong(self): """ Default error views should raise TemplateDoesNotExist when passed a template that doesn't exist. """ rf = RequestFactory() request = rf.get('/') with self.assertRaises(TemplateDoesNotExist): bad_request(request, Exception(), template_name='nonexistent') with self.assertRaises(TemplateDoesNotExist): permission_denied(request, Exception(), template_name='nonexistent') with self.assertRaises(TemplateDoesNotExist): page_not_found(request, Http404(), template_name='nonexistent') with self.assertRaises(TemplateDoesNotExist): server_error(request, template_name='nonexistent')