diff --git a/django/views/defaults.py b/django/views/defaults.py
index 2bbc23321e..ec7a233ff7 100644
--- a/django/views/defaults.py
+++ b/django/views/defaults.py
@@ -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(
+ '
Not Found
'
+ 'The requested URL {{ request_path }} was not found on this server.
')
+ 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('Server Error (500)
')
+ return http.HttpResponseServerError(template.render(Context({})))
# This can be called when CsrfViewMiddleware.process_view has not run,
diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt
index d6f95008de..f3501026f8 100644
--- a/docs/intro/tutorial03.txt
+++ b/docs/intro/tutorial03.txt
@@ -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:
diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt
index 38cedc40fe..7ff9165642 100644
--- a/docs/ref/contrib/flatpages.txt
+++ b/docs/ref/contrib/flatpages.txt
@@ -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.
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index 41fb2882a7..d87efda0af 100644
--- a/docs/releases/1.5.txt
+++ b/docs/releases/1.5.txt
@@ -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
=====================================
diff --git a/docs/topics/http/views.txt b/docs/topics/http/views.txt
index c4bd15e72e..7c4d1bbb6e 100644
--- a/docs/topics/http/views.txt
+++ b/docs/topics/http/views.txt
@@ -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
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index 41f40e7467..a150d1ce2a 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -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),
diff --git a/tests/regressiontests/test_client_regress/tests.py b/tests/regressiontests/test_client_regress/tests.py
index c741903c34..f424321663 100644
--- a/tests/regressiontests/test_client_regress/tests.py
+++ b/tests/regressiontests/test_client_regress/tests.py
@@ -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'),)
)
diff --git a/tests/regressiontests/views/tests/defaults.py b/tests/regressiontests/views/tests/defaults.py
index 2dd40b4a1a..3ca7f79136 100644
--- a/tests/regressiontests/views/tests/defaults.py
+++ b/tests/regressiontests/views/tests/defaults.py
@@ -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),
diff --git a/tests/templates/404.html b/tests/templates/404.html
deleted file mode 100644
index da627e2222..0000000000
--- a/tests/templates/404.html
+++ /dev/null
@@ -1 +0,0 @@
-Django Internal Tests: 404 Error
\ No newline at end of file
diff --git a/tests/templates/500.html b/tests/templates/500.html
deleted file mode 100644
index ff028cbeb0..0000000000
--- a/tests/templates/500.html
+++ /dev/null
@@ -1 +0,0 @@
-Django Internal Tests: 500 Error
\ No newline at end of file