mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Added "pretty" error pages to be used when DEBUG is True.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@1233 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -86,14 +86,14 @@ class BaseHandler: | ||||
|             return response | ||||
|         except exceptions.Http404, e: | ||||
|             if DEBUG: | ||||
|                 return self.get_technical_error_response(is404=True, exception=e) | ||||
|                 return self.get_technical_error_response(request, is404=True, exception=e) | ||||
|             else: | ||||
|                 callback, param_dict = resolver.resolve404() | ||||
|                 return callback(request, **param_dict) | ||||
|         except db.DatabaseError: | ||||
|             db.db.rollback() | ||||
|             if DEBUG: | ||||
|                 return self.get_technical_error_response() | ||||
|                 return self.get_technical_error_response(request) | ||||
|             else: | ||||
|                 subject = 'Database error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', '')) | ||||
|                 message = "%s\n\n%s" % (self._get_traceback(), request) | ||||
| @@ -103,7 +103,7 @@ class BaseHandler: | ||||
|             return httpwrappers.HttpResponseForbidden('<h1>Permission denied</h1>') | ||||
|         except: # Handle everything else, including SuspiciousOperation, etc. | ||||
|             if DEBUG: | ||||
|                 return self.get_technical_error_response() | ||||
|                 return self.get_technical_error_response(request) | ||||
|             else: | ||||
|                 subject = 'Coding error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', '')) | ||||
|                 try: | ||||
| @@ -123,35 +123,17 @@ class BaseHandler: | ||||
|         callback, param_dict = resolver.resolve500() | ||||
|         return callback(request, **param_dict) | ||||
|  | ||||
|     def get_technical_error_response(self, is404=False, exception=None): | ||||
|     def get_technical_error_response(self, request, is404=False, exception=None): | ||||
|         """ | ||||
|         Returns an HttpResponse that displays a TECHNICAL error message for a | ||||
|         fundamental database or coding error. | ||||
|         """ | ||||
|         import sys | ||||
|         from django.views import debug | ||||
|         if is404: | ||||
|             from django.conf.settings import ROOT_URLCONF | ||||
|             from django.utils.html import escape | ||||
|             html = ['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'] | ||||
|             html.append('<html><head><title>Error 404</title>') | ||||
|             # Explicitly tell robots not to archive this, in case this slips | ||||
|             # onto a production site. | ||||
|             html.append('<meta name="robots" content="NONE,NOARCHIVE" />') | ||||
|             html.append('</head><body><h1>Error 404</h1>') | ||||
|             try: | ||||
|                 tried = exception.args[0]['tried'] | ||||
|             except (IndexError, TypeError): | ||||
|                 if exception.args: | ||||
|                     html.append('<p>%s</p>' % escape(exception.args[0])) | ||||
|             else: | ||||
|                 html.append('<p>Using the URLconf defined in <code>%s</code>, Django tried these URL patterns, in this order:</p>' % ROOT_URLCONF) | ||||
|                 html.append('<ul>%s</ul>' % ''.join(['<li><code>%s</code></li>' % escape(t).replace(' ', ' ') for t in tried])) | ||||
|                 html.append("<p>The current URL, <code><strong>%r</strong></code>, didn't match any of these.</p>" % exception.args[0]['path']) | ||||
|             html.append("<hr /><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>") | ||||
|             html.append('</body></html>') | ||||
|             return httpwrappers.HttpResponseNotFound('\n'.join(html)) | ||||
|             return debug.technical_404_response(request, exception) | ||||
|         else: | ||||
|             output = "There's been an error:\n\n%s" % self._get_traceback() | ||||
|             return httpwrappers.HttpResponseServerError(output, mimetype='text/plain') | ||||
|             return debug.technical_500_response(request, *sys.exc_info()) | ||||
|  | ||||
|     def _get_traceback(self): | ||||
|         "Helper function to return the traceback as a string" | ||||
|   | ||||
							
								
								
									
										438
									
								
								django/views/debug.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										438
									
								
								django/views/debug.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,438 @@ | ||||
| import os | ||||
| import sys | ||||
| import inspect | ||||
| from django.conf import settings | ||||
| from os.path import dirname, join as pathjoin | ||||
| from django.core.template import Template, Context | ||||
| from django.utils.httpwrappers import HttpResponseServerError, HttpResponseNotFound | ||||
|  | ||||
| def technical_500_response(request, exc_type, exc_value, tb): | ||||
|     """ | ||||
|     Create a technical server error response.  The last three arguments are | ||||
|     the values returned from sys.exc_info() and friends. | ||||
|     """ | ||||
|     frames = [] | ||||
|     while tb is not None: | ||||
|         filename = tb.tb_frame.f_code.co_filename | ||||
|         function = tb.tb_frame.f_code.co_name | ||||
|         lineno = tb.tb_lineno - 1 | ||||
|         pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7) | ||||
|         frames.append({ | ||||
|             'tb' : tb, | ||||
|             'filename' : filename, | ||||
|             'function' : function, | ||||
|             'lineno' : lineno, | ||||
|             'vars' : tb.tb_frame.f_locals, | ||||
|             'id' : id(tb), | ||||
|             'pre_context' : pre_context, | ||||
|             'context_line' : context_line, | ||||
|             'post_context' : post_context, | ||||
|             'pre_context_lineno' : pre_context_lineno, | ||||
|         }) | ||||
|         tb = tb.tb_next | ||||
|          | ||||
|     t = Template(TECHNICAL_500_TEMPLATE) | ||||
|     c = Context({ | ||||
|         'exception_type' : exc_type.__name__, | ||||
|         'exception_value' : exc_value, | ||||
|         'frames' : frames, | ||||
|         'lastframe' : frames[-1], | ||||
|         'request' : request, | ||||
|         'request_protocol' : os.environ.get("HTTPS") == "on" and "https" or "http", | ||||
|         'settings' : dict([(k, getattr(settings, k)) for k in dir(settings) if k.isupper()]), | ||||
|          | ||||
|     }) | ||||
|     return HttpResponseServerError(t.render(c)) | ||||
|  | ||||
| def technical_404_response(request, exception): | ||||
|     """ | ||||
|     Create a technical 404 error response.  The exception should be the Http404 | ||||
|     exception. | ||||
|     """ | ||||
|     try: | ||||
|         tried = exception.args[0]['tried'] | ||||
|     except (IndexError, TypeError): | ||||
|         tried = [] | ||||
|          | ||||
|     t = Template(TECHNICAL_404_TEMPLATE) | ||||
|     c = Context({ | ||||
|         'root_urlconf' : settings.ROOT_URLCONF, | ||||
|         'urlpatterns' : tried, | ||||
|         'reason' : str(exception), | ||||
|         'request' : request, | ||||
|         'request_protocol' : os.environ.get("HTTPS") == "on" and "https" or "http", | ||||
|         'settings' : dict([(k, getattr(settings, k)) for k in dir(settings) if k.isupper()]), | ||||
|     }) | ||||
|     return HttpResponseNotFound(t.render(c)) | ||||
|  | ||||
| def _get_lines_from_file(filename, lineno, context_lines): | ||||
|     """ | ||||
|     Returns context_lines before and after lineno from file.   | ||||
|     Returns (pre_context_lineno, pre_context, context_line, post_context). | ||||
|     """ | ||||
|     try: | ||||
|         source = open(filename).readlines() | ||||
|         lower_bound = max(0, lineno - context_lines) | ||||
|         upper_bound = lineno + context_lines | ||||
|  | ||||
|         pre_context = [line.strip('\n') for line in source[lower_bound:lineno]] | ||||
|         context_line = source[lineno].strip('\n') | ||||
|         post_context = [line.strip('\n') for line in source[lineno+1:upper_bound]] | ||||
|          | ||||
|         return lower_bound, pre_context, context_line, post_context | ||||
|     except (OSError, IOError): | ||||
|         return None, [], None, [] | ||||
|  | ||||
| # | ||||
| # Templates are embedded in the file so that we know the error handler will | ||||
| # always work even if the template loader is broken. | ||||
| # | ||||
|  | ||||
| TECHNICAL_500_TEMPLATE = """ | ||||
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta http-equiv="content-type" content="text/html; charset=utf-8" /> | ||||
|   <title>{{ exception_type }} at {{ request.path }}</title> | ||||
|   <style type="text/css"> | ||||
|     html * { padding:0; margin:0; } | ||||
|     body * { padding:10px 20px; } | ||||
|     body * * { padding:0; } | ||||
|     body { font:small sans-serif; } | ||||
|     body>div { border-bottom:1px solid #ddd; } | ||||
|     h1 { font-weight:normal; } | ||||
|     h2 { margin-bottom:.8em; } | ||||
|     h2 span { font-size:80%; color:#666; font-weight:normal; } | ||||
|     h3 { margin:1em 0 .5em 0; } | ||||
|     h4 { margin:0 0 .5em 0; font-weight: normal; } | ||||
|     table { border:1px solid #ccc; border-collapse: collapse; width:100%; background:white; } | ||||
|     tbody td, tbody th { vertical-align:top; padding:2px 3px; } | ||||
|     thead th { padding:1px 6px 1px 3px; background:#fefefe; text-align:left; font-weight:normal; font-size:11px; border:1px solid #ddd; } | ||||
|     tbody th { width:12em; text-align:right; color:#666; padding-right:.5em; } | ||||
|     table.vars { margin:5px 0 2px 40px; } | ||||
|     table.vars td, table.req td { font-family:monospace; } | ||||
|     table td.code { width:100%; } | ||||
|     table td.code div { overflow:hidden; } | ||||
|     ul.traceback { list-style-type:none; } | ||||
|     ul.traceback li.frame { margin-bottom:1em; } | ||||
|     div.context { margin: 10px 0; } | ||||
|     div.context ol { padding-left:30px; margin:0 10px; list-style-position: inside; } | ||||
|     div.context ol li { font-family:monospace; white-space:pre; color:#666; } | ||||
|     div.context ol.context-line li { color:black; background-color:#ccc; cursor:pointer; } | ||||
|     div.commands { margin-left: 40px; } | ||||
|     div.commands a { color:black; text-decoration:none; } | ||||
|     #summary { background: #ffc; } | ||||
|     #summary h2 { font-weight: normal; color: #666; } | ||||
|     #explanation { background:#eee; } | ||||
|     #traceback { background:#eee; } | ||||
|     #requestinfo { background:#f6f6f6; padding-left:120px; } | ||||
|     #summary table { border:none; background:transparent; } | ||||
|     #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; } | ||||
|     #requestinfo h3 { margin-bottom:-1em; } | ||||
|   </style> | ||||
|   <script type="text/javascript"> | ||||
|     function getElementsByClassName(oElm, strTagName, strClassName){ | ||||
|         // Written by Jonathan Snook, http://www.snook.ca/jon; Add-ons by Robert Nyman, http://www.robertnyman.com | ||||
|         var arrElements = (strTagName == "*" && document.all)? document.all :  | ||||
|         oElm.getElementsByTagName(strTagName); | ||||
|         var arrReturnElements = new Array(); | ||||
|         strClassName = strClassName.replace(/\-/g, "\\-"); | ||||
|         var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)"); | ||||
|         var oElement; | ||||
|         for(var i=0; i<arrElements.length; i++){ | ||||
|             oElement = arrElements[i];       | ||||
|             if(oRegExp.test(oElement.className)){ | ||||
|                 arrReturnElements.push(oElement); | ||||
|             }    | ||||
|         } | ||||
|         return (arrReturnElements) | ||||
|     } | ||||
|     function hideAll(elems) { | ||||
|       for (var e = 0; e < elems.length; e++) {  | ||||
|         elems[e].style.display = 'none';  | ||||
|       } | ||||
|     } | ||||
|     window.onload = function() { | ||||
|       hideAll(getElementsByClassName(document, 'table', 'vars')); | ||||
|       hideAll(getElementsByClassName(document, 'ol', 'pre-context')); | ||||
|       hideAll(getElementsByClassName(document, 'ol', 'post-context')); | ||||
|     } | ||||
|     function toggle() { | ||||
|       for (var i = 0; i < arguments.length; i++) { | ||||
|         var e = document.getElementById(arguments[i]); | ||||
|         if (e) { | ||||
|           e.style.display = e.style.display == 'none' ? 'block' : 'none'; | ||||
|         } | ||||
|       } | ||||
|       return false; | ||||
|     } | ||||
|     function varToggle(link, id) { | ||||
|       toggle('v' + id); | ||||
|       var s = link.getElementsByTagName('span')[0]; | ||||
|       var uarr = String.fromCharCode(0x2191); | ||||
|       var darr = String.fromCharCode(0x2193); | ||||
|       s.innerHTML = s.innerHTML == uarr ? darr : uarr; | ||||
|       return false; | ||||
|     } | ||||
|   </script> | ||||
| </head> | ||||
| <body> | ||||
|  | ||||
| <div id="summary"> | ||||
|   <h1>{{ exception_type }} at {{ request.path }}</h1> | ||||
|   <h2>{{ exception_value }}</h2> | ||||
|   <table class="meta"> | ||||
|     <tr> | ||||
|       <th>Request Method:</th> | ||||
|       <td>{{ request.META.REQUEST_METHOD }}</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <th>Request URL:</th> | ||||
|       <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path }}</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <th>Exception Type:</th> | ||||
|       <td>{{ exception_type }}</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <th>Exception Value:</th> | ||||
|       <td>{{ exception_value }}</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <th>Exception Location:</th> | ||||
|       <td>{{ lastframe.filename }} in {{ lastframe.function }}, line {{ lastframe.lineno }}</td> | ||||
|     </tr> | ||||
|   </table> | ||||
| </div> | ||||
|  | ||||
| <div id="traceback"> | ||||
|   <h2>Traceback <span>(innermost last)</span></h2> | ||||
|   <ul class="traceback"> | ||||
|     {% for frame in frames %} | ||||
|       <li class="frame"> | ||||
|         <code>{{ frame.filename }}</code> in <code>{{ frame.function }}</code> | ||||
|          | ||||
|         {% if frame.context_line %} | ||||
|           <div class="context" id="c{{ frame.id }}"> | ||||
|             {% if frame.pre_context %} | ||||
|               <ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li>{{ line|escape }}</li>{% endfor %}</ol> | ||||
|             {% endif %} | ||||
|             <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line|escape }}</li></ol> | ||||
|             {% if frame.post_context %} | ||||
|               <ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li>{{ line|escape }}</li>{% endfor %}</ol> | ||||
|             {% endif %} | ||||
|           </div> | ||||
|         {% endif %} | ||||
|      | ||||
|         {% if frame.vars %} | ||||
|           <div class="commands"> | ||||
|               <a href="#" onclick="return varToggle(this, '{{ frame.id }}')">Local vars <span>↓</span> </a> | ||||
|           </div> | ||||
|           <table class="vars" id="v{{ frame.id }}"> | ||||
|             <thead> | ||||
|               <tr> | ||||
|                 <th>Variable</th> | ||||
|                 <th>Value</th> | ||||
|               </tr> | ||||
|             </thead> | ||||
|             <tbody> | ||||
|               {% for var in frame.vars.items|dictsort:"0" %} | ||||
|                 <tr> | ||||
|                   <td>{{ var.0 }}</td> | ||||
|                   <td class="code"><div>{{ var.1|pprint|escape }}</div></td> | ||||
|                 </tr> | ||||
|               {% endfor %} | ||||
|             </tbody> | ||||
|           </table> | ||||
|         {% endif %} | ||||
|       </li> | ||||
|     {% endfor %} | ||||
|   </ul> | ||||
| </div> | ||||
|  | ||||
| <div id="requestinfo"> | ||||
|   <h2>Request information</h2> | ||||
|    | ||||
|   <h3 id="get-info">GET</h3> | ||||
|   {% if request.GET %} | ||||
|     <table class="req"> | ||||
|       <thead> | ||||
|         <tr> | ||||
|           <th>Variable</th> | ||||
|           <th>Value</th> | ||||
|         </tr> | ||||
|       </thead> | ||||
|       </tbody> | ||||
|         {% for var in request.GET.items %} | ||||
|           <tr> | ||||
|             <td>{{ var.0 }}</td> | ||||
|             <td class="code"><div>{{ var.1|pprint|escape }}</div></td> | ||||
|           </tr> | ||||
|         {% endfor %} | ||||
|       </tbody> | ||||
|     </table> | ||||
|   {% else %} | ||||
|     <p>No GET data<p> | ||||
|   {% endif %} | ||||
|    | ||||
|   <h3 id="post-info">POST</h3> | ||||
|   {% if request.POST %} | ||||
|     <table class="req"> | ||||
|       <thead> | ||||
|         <tr> | ||||
|           <th>Variable</th> | ||||
|           <th>Value</th> | ||||
|         </tr> | ||||
|       </thead> | ||||
|       </tbody> | ||||
|         {% for var in request.POST.items %} | ||||
|           <tr> | ||||
|             <td>{{ var.0 }}</td> | ||||
|             <td class="code"><div>{{ var.1|pprint|escape }}</div></td> | ||||
|           </tr> | ||||
|         {% endfor %} | ||||
|       </tbody> | ||||
|     </table> | ||||
|   {% else %} | ||||
|     <p>No POST data<p> | ||||
|   {% endif %} | ||||
|    | ||||
|   <h3 id="cookie-info">COOKIES</h3> | ||||
|   {% if request.COOKIES %} | ||||
|     <table class="req"> | ||||
|       <thead> | ||||
|         <tr> | ||||
|           <th>Variable</th> | ||||
|           <th>Value</th> | ||||
|         </tr> | ||||
|       </thead> | ||||
|       </tbody> | ||||
|         {% for var in request.COOKIES.items %} | ||||
|           <tr> | ||||
|             <td>{{ var.0 }}</td> | ||||
|             <td class="code"><div>{{ var.1|pprint|escape }}</div></td> | ||||
|           </tr> | ||||
|         {% endfor %} | ||||
|       </tbody> | ||||
|     </table> | ||||
|   {% else %} | ||||
|     <p>No cookie data<p> | ||||
|   {% endif %} | ||||
|    | ||||
|   <h3 id="meta-info">META</h3> | ||||
|   <table class="req"> | ||||
|     <thead> | ||||
|       <tr> | ||||
|         <th>Variable</th> | ||||
|         <th>Value</th> | ||||
|       </tr> | ||||
|     </thead> | ||||
|     </tbody> | ||||
|       {% for var in request.META.items|dictsort:"0" %} | ||||
|         <tr> | ||||
|           <td>{{ var.0 }}</td> | ||||
|           <td class="code"><div>{{ var.1|pprint|escape }}</div></td> | ||||
|         </tr> | ||||
|       {% endfor %} | ||||
|     </tbody> | ||||
|   </table> | ||||
|  | ||||
|   <h3 id="settings-info">Settings</h3> | ||||
|   <h4>Using settings module <code>{{ settings.SETTINGS_MODULE }}</code></h4> | ||||
|   <table class="req"> | ||||
|     <thead> | ||||
|       <tr> | ||||
|         <th>Setting</th> | ||||
|         <th>Value</th> | ||||
|       </tr> | ||||
|     </thead> | ||||
|     </tbody> | ||||
|       {% for var in settings.items|dictsort:"0" %} | ||||
|         <tr> | ||||
|           <td>{{ var.0 }}</td> | ||||
|           <td class="code"><div>{{ var.1|pprint|escape }}</div></td> | ||||
|         </tr> | ||||
|       {% endfor %} | ||||
|     </tbody> | ||||
|   </table> | ||||
|  | ||||
| </div> | ||||
|  | ||||
| <div 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 500 page. | ||||
|   </p> | ||||
| </div> | ||||
|  | ||||
| </body> | ||||
| </html> | ||||
| """ | ||||
|  | ||||
| TECHNICAL_404_TEMPLATE = """ | ||||
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta http-equiv="content-type" content="text/html; charset=utf-8" /> | ||||
|   <title>Page not found at {{ request.path }}</title> | ||||
|   <meta name="robots" content="NONE,NOARCHIVE" /> | ||||
|   <style type="text/css"> | ||||
|     html * { padding:0; margin:0; } | ||||
|     body * { padding:10px 20px; } | ||||
|     body * * { padding:0; } | ||||
|     body { font:small sans-serif; background:#eee; } | ||||
|     body>div { border-bottom:1px solid #ddd; } | ||||
|     h1 { font-weight:normal; margin-bottom:.4em; } | ||||
|     h1 span { 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; } | ||||
|     #info { background:#f6f6f6; } | ||||
|     #info ol { margin: 0.5em 4em; } | ||||
|     #info ol li { font-family: monospace; } | ||||
|     #summary { background: #ffc; } | ||||
|     #explanation { background:#eee; border-bottom: 0px none; } | ||||
|   </style> | ||||
| </head> | ||||
| <body> | ||||
|   <div id="summary"> | ||||
|     <h1>Page not found <span>(404)</span></h1> | ||||
|     <table class="meta"> | ||||
|       <tr> | ||||
|         <th>Request Method:</th> | ||||
|         <td>{{ request.META.REQUEST_METHOD }}</td> | ||||
|       </tr> | ||||
|       <tr> | ||||
|         <th>Request URL:</th> | ||||
|       <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path }}</td> | ||||
|       </tr> | ||||
|     </table> | ||||
|   </div> | ||||
|   <div id="info"> | ||||
|     {% if urlpatterns %} | ||||
|       <p> | ||||
|         Using the URLconf defined in <code>{{ settings.ROOT_URLCONF }}</code>, | ||||
|         Django tried these URL patterns, in this order: | ||||
|       </p> | ||||
|       <ol> | ||||
|         {% for pattern in urlpatterns %} | ||||
|           <li>{{ pattern|escape }}</li> | ||||
|         {% endfor %} | ||||
|       </ol> | ||||
|       <p>The current URL, <code>{{ request.path }}</code>, didn't match any of these.</p>  | ||||
|     {% else %} | ||||
|       <p>{{ reason|escape }}</p> | ||||
|     {% endif %} | ||||
|   </div> | ||||
|    | ||||
|   <div 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> | ||||
| </body> | ||||
| </html> | ||||
| """ | ||||
		Reference in New Issue
	
	Block a user