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.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.
|
||||
|
||||
|
@ -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>')
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)})
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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``.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -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…
Reference in New Issue