Fixed #18807 -- Made 404.html and 500.html optional

Thanks Aymeric Augustin for the report and Jannis Leidel for the
review.
This commit is contained in:
Claude Paroz 2012-09-30 23:16:14 +02:00
parent 864a0514b8
commit 8bd7b598b6
10 changed files with 58 additions and 50 deletions

View File

@ -1,6 +1,6 @@
from django import http
from django.template import (Context, RequestContext,
loader, TemplateDoesNotExist)
loader, Template, TemplateDoesNotExist)
from django.views.decorators.csrf import requires_csrf_token
@ -17,8 +17,13 @@ def page_not_found(request, template_name='404.html'):
request_path
The path of the requested URL (e.g., '/app/pages/bad_page/')
"""
t = loader.get_template(template_name) # You need to create a 404.html template.
return http.HttpResponseNotFound(t.render(RequestContext(request, {'request_path': request.path})))
try:
template = loader.get_template(template_name)
except TemplateDoesNotExist:
template = Template(
'<h1>Not Found</h1>'
'<p>The requested URL {{ request_path }} was not found on this server.</p>')
return http.HttpResponseNotFound(template.render(RequestContext(request, {'request_path': request.path})))
@requires_csrf_token
@ -29,8 +34,11 @@ def server_error(request, template_name='500.html'):
Templates: :template:`500.html`
Context: None
"""
t = loader.get_template(template_name) # You need to create a 500.html template.
return http.HttpResponseServerError(t.render(Context({})))
try:
template = loader.get_template(template_name)
except TemplateDoesNotExist:
return http.HttpResponseServerError('<h1>Server Error (500)</h1>')
return http.HttpResponseServerError(template.render(Context({})))
# This can be called when CsrfViewMiddleware.process_view has not run,

View File

@ -366,11 +366,10 @@ special: It's just a normal view.
You normally won't have to bother with writing 404 views. If you don't set
``handler404``, the built-in view :func:`django.views.defaults.page_not_found`
is used by default. In this case, you still have one obligation: create a
``404.html`` template in the root of your template directory. The default 404
view will use that template for all 404 errors. If :setting:`DEBUG` is set to
``False`` (in your settings module) and if you didn't create a ``404.html``
file, an ``Http500`` is raised instead. So remember to create a ``404.html``.
is used by default. Optionally, you can create a ``404.html`` template
in the root of your template directory. The default 404 view will then use that
template for all 404 errors when :setting:`DEBUG` is set to ``False`` (in your
settings module).
A couple more things to note about 404 views:

View File

@ -158,9 +158,7 @@ For more on middleware, read the :doc:`middleware docs
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
only steps in once another view has successfully produced a 404 response.
If another view or middleware class attempts to produce a 404 but ends up
raising an exception instead (such as a ``TemplateDoesNotExist``
exception if your site does not have an appropriate template to
use for HTTP 404 responses), the response will become an HTTP 500
raising an exception instead, the response will become an HTTP 500
("Internal Server Error") and the
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
will not attempt to serve a flat page.

View File

@ -185,6 +185,12 @@ Django 1.5 also includes several smaller improvements worth noting:
look up permissions by using ``{% if 'someapp.someperm' in perms %}``
in templates.
* It's not required any more to have ``404.html`` and ``500.html`` templates in
the root templates directory. Django will output some basic error messages for
both situations when those templates are not found. Of course, it's still
recommended as good practice to provide those templates in order to present
pretty error pages to the user.
Backwards incompatible changes in 1.5
=====================================

View File

@ -134,13 +134,12 @@ The 404 (page not found) view
When you raise an ``Http404`` exception, Django loads a special view devoted
to handling 404 errors. By default, it's the view
``django.views.defaults.page_not_found``, which loads and renders the template
``404.html``.
``django.views.defaults.page_not_found``, which either produces a very simple
"Not Found" message or loads and renders the template ``404.html`` if you
created it in your root template directory.
This means you need to define a ``404.html`` template in your root template
directory. This template will be used for all 404 errors. The default 404 view
will pass one variable to the template: ``request_path``, which is the URL
that resulted in the error.
The default 404 view will pass one variable to the template: ``request_path``,
which is the URL that resulted in the error.
The ``page_not_found`` view should suffice for 99% of Web applications, but if
you want to override it, you can specify ``handler404`` in your URLconf, like
@ -152,15 +151,11 @@ Behind the scenes, Django determines the 404 view by looking for
``handler404`` in your root URLconf, and falling back to
``django.views.defaults.page_not_found`` if you did not define one.
Four things to note about 404 views:
Three things to note about 404 views:
* The 404 view is also called if Django doesn't find a match after
checking every regular expression in the URLconf.
* If you don't define your own 404 view — and simply use the default,
which is recommended — you still have one obligation: you must create a
``404.html`` template in the root of your template directory.
* The 404 view is passed a :class:`~django.template.RequestContext` and
will have access to variables supplied by your
:setting:`TEMPLATE_CONTEXT_PROCESSORS` setting (e.g., ``MEDIA_URL``).
@ -176,13 +171,12 @@ The 500 (server error) view
Similarly, Django executes special-case behavior in the case of runtime errors
in view code. If a view results in an exception, Django will, by default, call
the view ``django.views.defaults.server_error``, which loads and renders the
template ``500.html``.
the view ``django.views.defaults.server_error``, which either produces a very
simple "Server Error" message or loads and renders the template ``500.html`` if
you created it in your root template directory.
This means you need to define a ``500.html`` template in your root template
directory. This template will be used for all server errors. The default 500
view passes no variables to this template and is rendered with an empty
``Context`` to lessen the chance of additional errors.
The default 500 view passes no variables to the ``500.html`` template and is
rendered with an empty ``Context`` to lessen the chance of additional errors.
This ``server_error`` view should suffice for 99% of Web applications, but if
you want to override the view, you can specify ``handler500`` in your URLconf,
@ -194,11 +188,7 @@ Behind the scenes, Django determines the 500 view by looking for
``handler500`` in your root URLconf, and falling back to
``django.views.defaults.server_error`` if you did not define one.
Two things to note about 500 views:
* If you don't define your own 500 view — and simply use the default,
which is recommended — you still have one obligation: you must create a
``500.html`` template in the root of your template directory.
One thing to note about 500 views:
* 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

View File

@ -229,11 +229,11 @@ class Templates(unittest.TestCase):
loader.template_source_loaders = (filesystem.Loader(),)
# We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
# point to a directory containing a 404.html file. Also that
# point to a directory containing a login.html file. Also that
# the file system and app directories loaders both inherit the
# load_template method from the BaseLoader class, so we only need
# to test one of them.
load_name = '404.html'
load_name = 'login.html'
template = loader.get_template(load_name)
template_name = template.nodelist[0].source[0].name
self.assertTrue(template_name.endswith(load_name),

View File

@ -628,15 +628,6 @@ class TemplateExceptionTests(TestCase):
if hasattr(template_loader, 'reset'):
template_loader.reset()
@override_settings(TEMPLATE_DIRS=(),)
def test_no_404_template(self):
"Missing templates are correctly reported by test client"
try:
response = self.client.get("/no_such_view/")
self.fail("Should get error about missing template")
except TemplateDoesNotExist:
pass
@override_settings(
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'bad_templates'),)
)

View File

@ -1,7 +1,8 @@
from __future__ import absolute_import
from __future__ import absolute_import, unicode_literals
from django.test import TestCase
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from django.test.utils import setup_test_template_loader, restore_template_loaders
from ..models import Author, Article, UrlArticle
@ -71,6 +72,23 @@ class DefaultsTests(TestCase):
response = self.client.get('/views/server_error/')
self.assertEqual(response.status_code, 500)
def test_custom_templates(self):
"""
Test that 404.html and 500.html templates are picked by their respective
handler.
"""
setup_test_template_loader(
{'404.html': 'This is a test template for a 404 error.',
'500.html': 'This is a test template for a 500 error.'}
)
try:
for code, url in ((404, '/views/non_existing_url/'), (500, '/views/server_error/')):
response = self.client.get(url)
self.assertContains(response, "test template for a %d error" % code,
status_code=code)
finally:
restore_template_loaders()
def test_get_absolute_url_attributes(self):
"A model can set attributes on the get_absolute_url method"
self.assertTrue(getattr(UrlArticle.get_absolute_url, 'purge', False),

View File

@ -1 +0,0 @@
Django Internal Tests: 404 Error

View File

@ -1 +0,0 @@
Django Internal Tests: 500 Error