Fixed #25697 -- Made default error views error when passed a nonexistent template_name.
This commit is contained in:
parent
8d5d472c6d
commit
21bf685f5e
|
@ -4,12 +4,17 @@ from django.utils import six
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.views.decorators.csrf import requires_csrf_token
|
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,
|
# This can be called when CsrfViewMiddleware.process_view has not run,
|
||||||
# therefore need @requires_csrf_token in case the template needs
|
# therefore need @requires_csrf_token in case the template needs
|
||||||
# {% csrf_token %}.
|
# {% csrf_token %}.
|
||||||
@requires_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.
|
Default 404 handler.
|
||||||
|
|
||||||
|
@ -40,6 +45,9 @@ def page_not_found(request, exception, template_name='404.html'):
|
||||||
body = template.render(context, request)
|
body = template.render(context, request)
|
||||||
content_type = None # Django will use DEFAULT_CONTENT_TYPE
|
content_type = None # Django will use DEFAULT_CONTENT_TYPE
|
||||||
except TemplateDoesNotExist:
|
except TemplateDoesNotExist:
|
||||||
|
if template_name != ERROR_404_TEMPLATE_NAME:
|
||||||
|
# Reraise if it's a missing custom template.
|
||||||
|
raise
|
||||||
template = Engine().from_string(
|
template = Engine().from_string(
|
||||||
'<h1>Not Found</h1>'
|
'<h1>Not Found</h1>'
|
||||||
'<p>The requested URL {{ request_path }} was not found on this server.</p>')
|
'<p>The requested URL {{ request_path }} was not found on this server.</p>')
|
||||||
|
@ -49,7 +57,7 @@ def page_not_found(request, exception, template_name='404.html'):
|
||||||
|
|
||||||
|
|
||||||
@requires_csrf_token
|
@requires_csrf_token
|
||||||
def server_error(request, template_name='500.html'):
|
def server_error(request, template_name=ERROR_500_TEMPLATE_NAME):
|
||||||
"""
|
"""
|
||||||
500 error handler.
|
500 error handler.
|
||||||
|
|
||||||
|
@ -59,12 +67,15 @@ def server_error(request, template_name='500.html'):
|
||||||
try:
|
try:
|
||||||
template = loader.get_template(template_name)
|
template = loader.get_template(template_name)
|
||||||
except TemplateDoesNotExist:
|
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('<h1>Server Error (500)</h1>', content_type='text/html')
|
||||||
return http.HttpResponseServerError(template.render())
|
return http.HttpResponseServerError(template.render())
|
||||||
|
|
||||||
|
|
||||||
@requires_csrf_token
|
@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.
|
400 error handler.
|
||||||
|
|
||||||
|
@ -74,6 +85,9 @@ def bad_request(request, exception, template_name='400.html'):
|
||||||
try:
|
try:
|
||||||
template = loader.get_template(template_name)
|
template = loader.get_template(template_name)
|
||||||
except TemplateDoesNotExist:
|
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')
|
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.
|
# No exception content is passed to the template, to not disclose any sensitive information.
|
||||||
return http.HttpResponseBadRequest(template.render())
|
return http.HttpResponseBadRequest(template.render())
|
||||||
|
@ -83,7 +97,7 @@ def bad_request(request, exception, template_name='400.html'):
|
||||||
# therefore need @requires_csrf_token in case the template needs
|
# therefore need @requires_csrf_token in case the template needs
|
||||||
# {% csrf_token %}.
|
# {% csrf_token %}.
|
||||||
@requires_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.
|
Permission denied (403) handler.
|
||||||
|
|
||||||
|
@ -96,6 +110,9 @@ def permission_denied(request, exception, template_name='403.html'):
|
||||||
try:
|
try:
|
||||||
template = loader.get_template(template_name)
|
template = loader.get_template(template_name)
|
||||||
except TemplateDoesNotExist:
|
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('<h1>403 Forbidden</h1>', content_type='text/html')
|
||||||
return http.HttpResponseForbidden(
|
return http.HttpResponseForbidden(
|
||||||
template.render(request=request, context={'exception': force_text(exception)})
|
template.render(request=request, context={'exception': force_text(exception)})
|
||||||
|
|
|
@ -93,6 +93,10 @@ Three things to note about 404 views:
|
||||||
second parameter, the exception that triggered the error. A useful
|
second parameter, the exception that triggered the error. A useful
|
||||||
representation of the exception is also passed in the template context.
|
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:
|
.. _http_internal_server_error_view:
|
||||||
|
|
||||||
The 500 (server error) view
|
The 500 (server error) view
|
||||||
|
@ -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
|
your 500 view will never be used, and the traceback will be displayed
|
||||||
instead, with some debug information.
|
instead, with some debug information.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.10
|
||||||
|
|
||||||
|
Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.
|
||||||
|
|
||||||
.. _http_forbidden_view:
|
.. _http_forbidden_view:
|
||||||
|
|
||||||
The 403 (HTTP Forbidden) view
|
The 403 (HTTP Forbidden) view
|
||||||
|
@ -148,6 +156,10 @@ view you can use code like this::
|
||||||
unicode representation of the exception is also passed in the template
|
unicode representation of the exception is also passed in the template
|
||||||
context.
|
context.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.10
|
||||||
|
|
||||||
|
Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.
|
||||||
|
|
||||||
.. _http_bad_request_view:
|
.. _http_bad_request_view:
|
||||||
|
|
||||||
The 400 (bad request) view
|
The 400 (bad request) view
|
||||||
|
@ -173,3 +185,7 @@ filesystem paths.
|
||||||
|
|
||||||
The signature of ``bad_request()`` changed in Django 1.9. The function
|
The signature of ``bad_request()`` changed in Django 1.9. The function
|
||||||
now accepts a second parameter, the exception that triggered the error.
|
now accepts a second parameter, the exception that triggered the error.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.10
|
||||||
|
|
||||||
|
Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.
|
||||||
|
|
|
@ -464,6 +464,9 @@ Miscellaneous
|
||||||
now better to call the ``LogEntry.get_change_message()`` method which will
|
now better to call the ``LogEntry.get_change_message()`` method which will
|
||||||
provide the message in the current language.
|
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:
|
.. _deprecated-features-1.10:
|
||||||
|
|
||||||
Features deprecated in 1.10
|
Features deprecated in 1.10
|
||||||
|
|
|
@ -4,8 +4,13 @@ import datetime
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.sites.models import Site
|
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.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
|
from ..models import Article, Author, UrlArticle
|
||||||
|
|
||||||
|
@ -123,3 +128,23 @@ class DefaultsTests(TestCase):
|
||||||
|
|
||||||
response = self.client.get('/server_error/')
|
response = self.client.get('/server_error/')
|
||||||
self.assertEqual(response['Content-Type'], 'text/html')
|
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…
Reference in New Issue