diff options
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | django/views/templates/technical_404.html | 27 | ||||
| -rw-r--r-- | django/views/templates/technical_500.html | 72 | ||||
| -rw-r--r-- | docs/releases/5.1.txt | 3 | ||||
| -rw-r--r-- | tests/view_tests/tests/test_debug.py | 73 |
5 files changed, 100 insertions, 76 deletions
@@ -638,6 +638,7 @@ answer newbie questions, and generally made Django that much better: Marc Tamlyn <marc.tamlyn@gmail.com> Marc-Aurèle Brothier <ma.brothier@gmail.com> Marian Andre <django@andre.sk> + Marijke Luttekes <mail@marijkeluttekes.dev> Marijn Vriens <marijn@metronomo.cl> Mario Gonzalez <gonzalemario@gmail.com> Mariusz Felisiak <felisiak.mariusz@gmail.com> diff --git a/django/views/templates/technical_404.html b/django/views/templates/technical_404.html index c47dae22af..f2bfe49372 100644 --- a/django/views/templates/technical_404.html +++ b/django/views/templates/technical_404.html @@ -9,9 +9,9 @@ body * { padding:10px 20px; } body * * { padding:0; } body { font:small sans-serif; background:#eee; color:#000; } - body>div { border-bottom:1px solid #ddd; } + body > :where(header, main, footer) { border-bottom:1px solid #ddd; } h1 { font-weight:normal; margin-bottom:.4em; } - h1 span { font-size:60%; color:#666; font-weight:normal; } + h1 small { font-size:60%; color:#666; font-weight:normal; } table { border:none; border-collapse: collapse; width:100%; } td, th { vertical-align:top; padding:2px 3px; } th { width:12em; text-align:right; color:#666; padding-right:.5em; } @@ -24,27 +24,28 @@ </style> </head> <body> - <div id="summary"> - <h1>Page not found <span>(404)</span></h1> + <header id="summary"> + <h1>Page not found <small>(404)</small></h1> {% if reason and resolved %}<pre class="exception_value">{{ reason }}</pre>{% endif %} <table class="meta"> <tr> - <th>Request Method:</th> + <th scope="row">Request Method:</th> <td>{{ request.META.REQUEST_METHOD }}</td> </tr> <tr> - <th>Request URL:</th> + <th scope="row">Request URL:</th> <td>{{ request.build_absolute_uri }}</td> </tr> {% if raising_view_name %} <tr> - <th>Raised by:</th> + <th scope="row">Raised by:</th> <td>{{ raising_view_name }}</td> </tr> {% endif %} </table> - </div> - <div id="info"> + </header> + + <main id="info"> {% if urlpatterns %} <p> Using the URLconf defined in <code>{{ urlconf }}</code>, @@ -54,8 +55,10 @@ {% for pattern in urlpatterns %} <li> {% for pat in pattern %} + <code> {{ pat.pattern }} {% if forloop.last and pat.name %}[name='{{ pat.name }}']{% endif %} + </code> {% endfor %} </li> {% endfor %} @@ -69,14 +72,14 @@ {% if resolved %}matched the last one.{% else %}didn’t match any of these.{% endif %} </p> {% endif %} - </div> + </main> - <div id="explanation"> + <footer id="explanation"> <p> You’re seeing this error because you have <code>DEBUG = True</code> in your Django settings file. Change that to <code>False</code>, and Django will display a standard 404 page. </p> - </div> + </footer> </body> </html> diff --git a/django/views/templates/technical_500.html b/django/views/templates/technical_500.html index a5c187147b..305c4655ad 100644 --- a/django/views/templates/technical_500.html +++ b/django/views/templates/technical_500.html @@ -10,7 +10,7 @@ body * { padding:10px 20px; } body * * { padding:0; } body { font:small sans-serif; background-color:#fff; color:#000; } - body>div { border-bottom:1px solid #ddd; } + body > :where(header, main, footer) { border-bottom:1px solid #ddd; } h1 { font-weight:normal; } h2 { margin-bottom:.8em; } h3 { margin:1em 0 .5em 0; } @@ -47,6 +47,8 @@ .user div.commands a { color: black; } #summary { background: #ffc; } #summary h2 { font-weight: normal; color: #666; } + #info { padding: 0; } + #info > * { padding:10px 20px; } #explanation { background:#eee; } #template, #template-not-exist { background:#f6f6f6; } #template-not-exist ul { margin: 0 0 10px 20px; } @@ -97,67 +99,69 @@ {% endif %} </head> <body> -<div id="summary"> +<header id="summary"> <h1>{% if exception_type %}{{ exception_type }}{% else %}Report{% endif %} {% if request %} at {{ request.path_info }}{% endif %}</h1> <pre class="exception_value">{% if exception_value %}{{ exception_value|force_escape }}{% if exception_notes %}{{ exception_notes }}{% endif %}{% else %}No exception message supplied{% endif %}</pre> <table class="meta"> {% if request %} <tr> - <th>Request Method:</th> + <th scope="row">Request Method:</th> <td>{{ request.META.REQUEST_METHOD }}</td> </tr> <tr> - <th>Request URL:</th> + <th scope="row">Request URL:</th> <td>{{ request_insecure_uri }}</td> </tr> {% endif %} <tr> - <th>Django Version:</th> + <th scope="row">Django Version:</th> <td>{{ django_version_info }}</td> </tr> {% if exception_type %} <tr> - <th>Exception Type:</th> + <th scope="row">Exception Type:</th> <td>{{ exception_type }}</td> </tr> {% endif %} {% if exception_type and exception_value %} <tr> - <th>Exception Value:</th> + <th scope="row">Exception Value:</th> <td><pre>{{ exception_value|force_escape }}</pre></td> </tr> {% endif %} {% if lastframe %} <tr> - <th>Exception Location:</th> + <th scope="row">Exception Location:</th> <td><span class="fname">{{ lastframe.filename }}</span>, line {{ lastframe.lineno }}, in {{ lastframe.function }}</td> </tr> {% endif %} {% if raising_view_name %} <tr> - <th>Raised during:</th> + <th scope="row">Raised during:</th> <td>{{ raising_view_name }}</td> </tr> {% endif %} <tr> - <th>Python Executable:</th> + <th scope="row">Python Executable:</th> <td>{{ sys_executable }}</td> </tr> <tr> - <th>Python Version:</th> + <th scope="row">Python Version:</th> <td>{{ sys_version_info }}</td> </tr> <tr> - <th>Python Path:</th> - <td><pre>{{ sys_path|pprint }}</pre></td> + <th scope="row">Python Path:</th> + <td><pre><code>{{ sys_path|pprint }}</code></pre></td> </tr> <tr> - <th>Server time:</th> + <th scope="row">Server time:</th> <td>{{server_time|date:"r"}}</td> </tr> </table> -</div> +</header> + +<main id="info"> {% if unicode_hint %} <div id="unicode-hint"> <h2>Unicode error hint</h2> @@ -195,11 +199,11 @@ {% if template_info.bottom != template_info.total %} cut-bottom{% endif %}"> {% for source_line in template_info.source_lines %} {% if source_line.0 == template_info.line %} - <tr class="error"><th>{{ source_line.0 }}</th> + <tr class="error"><th scope="row">{{ source_line.0 }}</th> <td>{{ template_info.before }}<span class="specific">{{ template_info.during }}</span>{{ template_info.after }}</td> </tr> {% else %} - <tr><th>{{ source_line.0 }}</th> + <tr><th scope="row">{{ source_line.0 }}</th> <td>{{ source_line.1 }}</td></tr> {% endif %} {% endfor %} @@ -266,8 +270,8 @@ <table class="vars" id="v{{ frame.id }}"> <thead> <tr> - <th>Variable</th> - <th>Value</th> + <th scope="col">Variable</th> + <th scope="col">Value</th> </tr> </thead> <tbody> @@ -354,8 +358,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex <table class="req"> <thead> <tr> - <th>Variable</th> - <th>Value</th> + <th scope="col">Variable</th> + <th scope="col">Value</th> </tr> </thead> <tbody> @@ -376,8 +380,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex <table class="req"> <thead> <tr> - <th>Variable</th> - <th>Value</th> + <th scope="col">Variable</th> + <th scope="col">Value</th> </tr> </thead> <tbody> @@ -398,8 +402,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex <table class="req"> <thead> <tr> - <th>Variable</th> - <th>Value</th> + <th scope="col">Variable</th> + <th scope="col">Value</th> </tr> </thead> <tbody> @@ -420,8 +424,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex <table class="req"> <thead> <tr> - <th>Variable</th> - <th>Value</th> + <th scope="col">Variable</th> + <th scope="col">Value</th> </tr> </thead> <tbody> @@ -441,8 +445,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex <table class="req"> <thead> <tr> - <th>Variable</th> - <th>Value</th> + <th scope="col">Variable</th> + <th scope="col">Value</th> </tr> </thead> <tbody> @@ -463,8 +467,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex <table class="req"> <thead> <tr> - <th>Setting</th> - <th>Value</th> + <th scope="col">Setting</th> + <th scope="col">Value</th> </tr> </thead> <tbody> @@ -478,14 +482,16 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex </table> </div> +</main> + {% if not is_email %} - <div id="explanation"> + <footer id="explanation"> <p> You’re seeing this error because you have <code>DEBUG = True</code> in your Django settings file. Change that to <code>False</code>, and Django will display a standard page generated by the handler for this status code. </p> - </div> + </footer> {% endif %} </body> </html> diff --git a/docs/releases/5.1.txt b/docs/releases/5.1.txt index 284c1f4f74..f166474607 100644 --- a/docs/releases/5.1.txt +++ b/docs/releases/5.1.txt @@ -156,7 +156,8 @@ Email Error Reporting ~~~~~~~~~~~~~~~ -* ... +* In order to improve accessibility, the technical 404 and 500 error pages now + use HTML landmark elements for the header, footer, and main content areas. File Storage ~~~~~~~~~~~~ diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index 03db07a61c..45a0dc70ee 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -178,6 +178,12 @@ class DebugViewTests(SimpleTestCase): ) self.assertContains( response, + "<code>technical404/ [name='my404']</code>", + status_code=404, + html=True, + ) + self.assertContains( + response, "<p>The current path, <code>not-in-urls</code>, didn’t match any " "of these.</p>", status_code=404, @@ -204,6 +210,9 @@ class DebugViewTests(SimpleTestCase): def test_technical_404(self): response = self.client.get("/technical404/") + self.assertContains(response, '<header id="summary">', status_code=404) + self.assertContains(response, '<main id="info">', status_code=404) + self.assertContains(response, '<footer id="explanation">', status_code=404) self.assertContains( response, '<pre class="exception_value">Testing technical 404.</pre>', @@ -228,7 +237,7 @@ class DebugViewTests(SimpleTestCase): response = self.client.get("/classbased404/") self.assertContains( response, - "<th>Raised by:</th><td>view_tests.views.Http404View</td>", + '<th scope="row">Raised by:</th><td>view_tests.views.Http404View</td>', status_code=404, html=True, ) @@ -236,9 +245,12 @@ class DebugViewTests(SimpleTestCase): def test_technical_500(self): with self.assertLogs("django.request", "ERROR"): response = self.client.get("/raises500/") + self.assertContains(response, '<header id="summary">', status_code=500) + self.assertContains(response, '<main id="info">', status_code=500) + self.assertContains(response, '<footer id="explanation">', status_code=500) self.assertContains( response, - "<th>Raised during:</th><td>view_tests.views.raises500</td>", + '<th scope="row">Raised during:</th><td>view_tests.views.raises500</td>', status_code=500, html=True, ) @@ -255,7 +267,8 @@ class DebugViewTests(SimpleTestCase): response = self.client.get("/classbased500/") self.assertContains( response, - "<th>Raised during:</th><td>view_tests.views.Raises500View</td>", + '<th scope="row">Raised during:</th>' + "<td>view_tests.views.Raises500View</td>", status_code=500, html=True, ) @@ -397,7 +410,7 @@ class DebugViewTests(SimpleTestCase): """ response = self.client.get("/") self.assertContains( - response, "Page not found <span>(404)</span>", status_code=404 + response, "Page not found <small>(404)</small>", status_code=404 ) def test_template_encoding(self): @@ -531,12 +544,12 @@ class ExceptionReporterTests(SimpleTestCase): self.assertIn( '<pre class="exception_value">Can't find my keys</pre>', html ) - self.assertIn("<th>Request Method:</th>", html) - self.assertIn("<th>Request URL:</th>", html) + self.assertIn('<th scope="row">Request Method:</th>', html) + self.assertIn('<th scope="row">Request URL:</th>', html) self.assertIn('<h3 id="user-info">USER</h3>', html) self.assertIn("<p>jacob</p>", html) - self.assertIn("<th>Exception Type:</th>", html) - self.assertIn("<th>Exception Value:</th>", html) + self.assertIn('<th scope="row">Exception Type:</th>', html) + self.assertIn('<th scope="row">Exception Value:</th>', html) self.assertIn("<h2>Traceback ", html) self.assertIn("<h2>Request information</h2>", html) self.assertNotIn("<p>Request data not supplied</p>", html) @@ -554,11 +567,11 @@ class ExceptionReporterTests(SimpleTestCase): self.assertIn( '<pre class="exception_value">Can't find my keys</pre>', html ) - self.assertNotIn("<th>Request Method:</th>", html) - self.assertNotIn("<th>Request URL:</th>", html) + self.assertNotIn('<th scope="row">Request Method:</th>', html) + self.assertNotIn('<th scope="row">Request URL:</th>', html) self.assertNotIn('<h3 id="user-info">USER</h3>', html) - self.assertIn("<th>Exception Type:</th>", html) - self.assertIn("<th>Exception Value:</th>", html) + self.assertIn('<th scope="row">Exception Type:</th>', html) + self.assertIn('<th scope="row">Exception Value:</th>', html) self.assertIn("<h2>Traceback ", html) self.assertIn("<h2>Request information</h2>", html) self.assertIn("<p>Request data not supplied</p>", html) @@ -603,10 +616,10 @@ class ExceptionReporterTests(SimpleTestCase): self.assertIn( '<pre class="exception_value">No exception message supplied</pre>', html ) - self.assertIn("<th>Request Method:</th>", html) - self.assertIn("<th>Request URL:</th>", html) - self.assertNotIn("<th>Exception Type:</th>", html) - self.assertNotIn("<th>Exception Value:</th>", html) + self.assertIn('<th scope="row">Request Method:</th>', html) + self.assertIn('<th scope="row">Request URL:</th>', html) + self.assertNotIn('<th scope="row">Exception Type:</th>', html) + self.assertNotIn('<th scope="row">Exception Value:</th>', html) self.assertNotIn("<h2>Traceback ", html) self.assertIn("<h2>Request information</h2>", html) self.assertNotIn("<p>Request data not supplied</p>", html) @@ -626,8 +639,8 @@ class ExceptionReporterTests(SimpleTestCase): self.assertIn( '<pre class="exception_value">Can't find my keys</pre>', html ) - self.assertIn("<th>Exception Type:</th>", html) - self.assertIn("<th>Exception Value:</th>", html) + self.assertIn('<th scope="row">Exception Type:</th>', html) + self.assertIn('<th scope="row">Exception Value:</th>', html) self.assertIn("<h2>Traceback ", html) self.assertIn("<h2>Request information</h2>", html) self.assertIn("<p>Request data not supplied</p>", html) @@ -650,8 +663,8 @@ class ExceptionReporterTests(SimpleTestCase): html = reporter.get_traceback_html() self.assertInHTML("<h1>RuntimeError</h1>", html) self.assertIn('<pre class="exception_value">Oops</pre>', html) - self.assertIn("<th>Exception Type:</th>", html) - self.assertIn("<th>Exception Value:</th>", html) + self.assertIn('<th scope="row">Exception Type:</th>', html) + self.assertIn('<th scope="row">Exception Value:</th>', html) self.assertIn("<h2>Traceback ", html) self.assertIn("<h2>Request information</h2>", html) self.assertIn("<p>Request data not supplied</p>", html) @@ -721,8 +734,8 @@ class ExceptionReporterTests(SimpleTestCase): html = reporter.get_traceback_html() self.assertInHTML("<h1>RuntimeError</h1>", html) self.assertIn('<pre class="exception_value">Oops</pre>', html) - self.assertIn("<th>Exception Type:</th>", html) - self.assertIn("<th>Exception Value:</th>", html) + self.assertIn('<th scope="row">Exception Type:</th>', html) + self.assertIn('<th scope="row">Exception Value:</th>', html) self.assertIn("<h2>Traceback ", html) self.assertInHTML('<li class="frame user">Traceback: None</li>', html) self.assertIn( @@ -981,10 +994,10 @@ class ExceptionReporterTests(SimpleTestCase): self.assertIn( '<pre class="exception_value">I'm a little teapot</pre>', html ) - self.assertIn("<th>Request Method:</th>", html) - self.assertIn("<th>Request URL:</th>", html) - self.assertNotIn("<th>Exception Type:</th>", html) - self.assertNotIn("<th>Exception Value:</th>", html) + self.assertIn('<th scope="row">Request Method:</th>', html) + self.assertIn('<th scope="row">Request URL:</th>', html) + self.assertNotIn('<th scope="row">Exception Type:</th>', html) + self.assertNotIn('<th scope="row">Exception Value:</th>', html) self.assertIn("<h2>Traceback ", html) self.assertIn("<h2>Request information</h2>", html) self.assertNotIn("<p>Request data not supplied</p>", html) @@ -996,10 +1009,10 @@ class ExceptionReporterTests(SimpleTestCase): self.assertIn( '<pre class="exception_value">I'm a little teapot</pre>', html ) - self.assertNotIn("<th>Request Method:</th>", html) - self.assertNotIn("<th>Request URL:</th>", html) - self.assertNotIn("<th>Exception Type:</th>", html) - self.assertNotIn("<th>Exception Value:</th>", html) + self.assertNotIn('<th scope="row">Request Method:</th>', html) + self.assertNotIn('<th scope="row">Request URL:</th>', html) + self.assertNotIn('<th scope="row">Exception Type:</th>', html) + self.assertNotIn('<th scope="row">Exception Value:</th>', html) self.assertIn("<h2>Traceback ", html) self.assertIn("<h2>Request information</h2>", html) self.assertIn("<p>Request data not supplied</p>", html) |
