web/lib/django/views/debug.py
changeset 38 77b6da96e6f1
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     1 import datetime
       
     2 import os
       
     3 import re
       
     4 import sys
       
     5 
       
     6 from django.conf import settings
       
     7 from django.http import HttpResponse, HttpResponseServerError, HttpResponseNotFound
       
     8 from django.template import (Template, Context, TemplateDoesNotExist,
       
     9     TemplateSyntaxError)
       
    10 from django.utils.html import escape
       
    11 from django.utils.importlib import import_module
       
    12 from django.utils.encoding import smart_unicode, smart_str
       
    13 
       
    14 
       
    15 HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
       
    16 
       
    17 def linebreak_iter(template_source):
       
    18     yield 0
       
    19     p = template_source.find('\n')
       
    20     while p >= 0:
       
    21         yield p+1
       
    22         p = template_source.find('\n', p+1)
       
    23     yield len(template_source) + 1
       
    24 
       
    25 def cleanse_setting(key, value):
       
    26     """Cleanse an individual setting key/value of sensitive content.
       
    27 
       
    28     If the value is a dictionary, recursively cleanse the keys in
       
    29     that dictionary.
       
    30     """
       
    31     try:
       
    32         if HIDDEN_SETTINGS.search(key):
       
    33             cleansed = '********************'
       
    34         else:
       
    35             if isinstance(value, dict):
       
    36                 cleansed = dict((k, cleanse_setting(k, v)) for k,v in value.items())
       
    37             else:
       
    38                 cleansed = value
       
    39     except TypeError:
       
    40         # If the key isn't regex-able, just return as-is.
       
    41         cleansed = value
       
    42     return cleansed
       
    43 
       
    44 def get_safe_settings():
       
    45     "Returns a dictionary of the settings module, with sensitive settings blurred out."
       
    46     settings_dict = {}
       
    47     for k in dir(settings):
       
    48         if k.isupper():
       
    49             settings_dict[k] = cleanse_setting(k, getattr(settings, k))
       
    50     return settings_dict
       
    51 
       
    52 def technical_500_response(request, exc_type, exc_value, tb):
       
    53     """
       
    54     Create a technical server error response. The last three arguments are
       
    55     the values returned from sys.exc_info() and friends.
       
    56     """
       
    57     reporter = ExceptionReporter(request, exc_type, exc_value, tb)
       
    58     html = reporter.get_traceback_html()
       
    59     return HttpResponseServerError(html, mimetype='text/html')
       
    60 
       
    61 class ExceptionReporter:
       
    62     """
       
    63     A class to organize and coordinate reporting on exceptions.
       
    64     """
       
    65     def __init__(self, request, exc_type, exc_value, tb):
       
    66         self.request = request
       
    67         self.exc_type = exc_type
       
    68         self.exc_value = exc_value
       
    69         self.tb = tb
       
    70 
       
    71         self.template_info = None
       
    72         self.template_does_not_exist = False
       
    73         self.loader_debug_info = None
       
    74 
       
    75         # Handle deprecated string exceptions
       
    76         if isinstance(self.exc_type, basestring):
       
    77             self.exc_value = Exception('Deprecated String Exception: %r' % self.exc_type)
       
    78             self.exc_type = type(self.exc_value)
       
    79 
       
    80     def get_traceback_html(self):
       
    81         "Return HTML code for traceback."
       
    82 
       
    83         if issubclass(self.exc_type, TemplateDoesNotExist):
       
    84             from django.template.loader import template_source_loaders
       
    85             self.template_does_not_exist = True
       
    86             self.loader_debug_info = []
       
    87             for loader in template_source_loaders:
       
    88                 try:
       
    89                     module = import_module(loader.__module__)
       
    90                     source_list_func = module.get_template_sources
       
    91                     # NOTE: This assumes exc_value is the name of the template that
       
    92                     # the loader attempted to load.
       
    93                     template_list = [{'name': t, 'exists': os.path.exists(t)} \
       
    94                         for t in source_list_func(str(self.exc_value))]
       
    95                 except (ImportError, AttributeError):
       
    96                     template_list = []
       
    97                 if hasattr(loader, '__class__'):
       
    98                     loader_name = loader.__module__ + '.' + loader.__class__.__name__
       
    99                 else:
       
   100                     loader_name = loader.__module__ + '.' + loader.__name__
       
   101                 self.loader_debug_info.append({
       
   102                     'loader': loader_name,
       
   103                     'templates': template_list,
       
   104                 })
       
   105         if (settings.TEMPLATE_DEBUG and hasattr(self.exc_value, 'source') and
       
   106             isinstance(self.exc_value, TemplateSyntaxError)):
       
   107             self.get_template_exception_info()
       
   108 
       
   109         frames = self.get_traceback_frames()
       
   110 
       
   111         unicode_hint = ''
       
   112         if issubclass(self.exc_type, UnicodeError):
       
   113             start = getattr(self.exc_value, 'start', None)
       
   114             end = getattr(self.exc_value, 'end', None)
       
   115             if start is not None and end is not None:
       
   116                 unicode_str = self.exc_value.args[1]
       
   117                 unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace')
       
   118         from django import get_version
       
   119         t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template')
       
   120         c = Context({
       
   121             'exception_type': self.exc_type.__name__,
       
   122             'exception_value': smart_unicode(self.exc_value, errors='replace'),
       
   123             'unicode_hint': unicode_hint,
       
   124             'frames': frames,
       
   125             'lastframe': frames[-1],
       
   126             'request': self.request,
       
   127             'settings': get_safe_settings(),
       
   128             'sys_executable': sys.executable,
       
   129             'sys_version_info': '%d.%d.%d' % sys.version_info[0:3],
       
   130             'server_time': datetime.datetime.now(),
       
   131             'django_version_info': get_version(),
       
   132             'sys_path' : sys.path,
       
   133             'template_info': self.template_info,
       
   134             'template_does_not_exist': self.template_does_not_exist,
       
   135             'loader_debug_info': self.loader_debug_info,
       
   136         })
       
   137         return t.render(c)
       
   138 
       
   139     def get_template_exception_info(self):
       
   140         origin, (start, end) = self.exc_value.source
       
   141         template_source = origin.reload()
       
   142         context_lines = 10
       
   143         line = 0
       
   144         upto = 0
       
   145         source_lines = []
       
   146         before = during = after = ""
       
   147         for num, next in enumerate(linebreak_iter(template_source)):
       
   148             if start >= upto and end <= next:
       
   149                 line = num
       
   150                 before = escape(template_source[upto:start])
       
   151                 during = escape(template_source[start:end])
       
   152                 after = escape(template_source[end:next])
       
   153             source_lines.append( (num, escape(template_source[upto:next])) )
       
   154             upto = next
       
   155         total = len(source_lines)
       
   156 
       
   157         top = max(1, line - context_lines)
       
   158         bottom = min(total, line + 1 + context_lines)
       
   159 
       
   160         self.template_info = {
       
   161             'message': self.exc_value.args[0],
       
   162             'source_lines': source_lines[top:bottom],
       
   163             'before': before,
       
   164             'during': during,
       
   165             'after': after,
       
   166             'top': top,
       
   167             'bottom': bottom,
       
   168             'total': total,
       
   169             'line': line,
       
   170             'name': origin.name,
       
   171         }
       
   172 
       
   173     def _get_lines_from_file(self, filename, lineno, context_lines, loader=None, module_name=None):
       
   174         """
       
   175         Returns context_lines before and after lineno from file.
       
   176         Returns (pre_context_lineno, pre_context, context_line, post_context).
       
   177         """
       
   178         source = None
       
   179         if loader is not None and hasattr(loader, "get_source"):
       
   180             source = loader.get_source(module_name)
       
   181             if source is not None:
       
   182                 source = source.splitlines()
       
   183         if source is None:
       
   184             try:
       
   185                 f = open(filename)
       
   186                 try:
       
   187                     source = f.readlines()
       
   188                 finally:
       
   189                     f.close()
       
   190             except (OSError, IOError):
       
   191                 pass
       
   192         if source is None:
       
   193             return None, [], None, []
       
   194 
       
   195         encoding = 'ascii'
       
   196         for line in source[:2]:
       
   197             # File coding may be specified. Match pattern from PEP-263
       
   198             # (http://www.python.org/dev/peps/pep-0263/)
       
   199             match = re.search(r'coding[:=]\s*([-\w.]+)', line)
       
   200             if match:
       
   201                 encoding = match.group(1)
       
   202                 break
       
   203         source = [unicode(sline, encoding, 'replace') for sline in source]
       
   204 
       
   205         lower_bound = max(0, lineno - context_lines)
       
   206         upper_bound = lineno + context_lines
       
   207 
       
   208         pre_context = [line.strip('\n') for line in source[lower_bound:lineno]]
       
   209         context_line = source[lineno].strip('\n')
       
   210         post_context = [line.strip('\n') for line in source[lineno+1:upper_bound]]
       
   211 
       
   212         return lower_bound, pre_context, context_line, post_context
       
   213 
       
   214     def get_traceback_frames(self):
       
   215         frames = []
       
   216         tb = self.tb
       
   217         while tb is not None:
       
   218             # support for __traceback_hide__ which is used by a few libraries
       
   219             # to hide internal frames.
       
   220             if tb.tb_frame.f_locals.get('__traceback_hide__'):
       
   221                 tb = tb.tb_next
       
   222                 continue
       
   223             filename = tb.tb_frame.f_code.co_filename
       
   224             function = tb.tb_frame.f_code.co_name
       
   225             lineno = tb.tb_lineno - 1
       
   226             loader = tb.tb_frame.f_globals.get('__loader__')
       
   227             module_name = tb.tb_frame.f_globals.get('__name__')
       
   228             pre_context_lineno, pre_context, context_line, post_context = self._get_lines_from_file(filename, lineno, 7, loader, module_name)
       
   229             if pre_context_lineno is not None:
       
   230                 frames.append({
       
   231                     'tb': tb,
       
   232                     'filename': filename,
       
   233                     'function': function,
       
   234                     'lineno': lineno + 1,
       
   235                     'vars': tb.tb_frame.f_locals.items(),
       
   236                     'id': id(tb),
       
   237                     'pre_context': pre_context,
       
   238                     'context_line': context_line,
       
   239                     'post_context': post_context,
       
   240                     'pre_context_lineno': pre_context_lineno + 1,
       
   241                 })
       
   242             tb = tb.tb_next
       
   243 
       
   244         if not frames:
       
   245             frames = [{
       
   246                 'filename': '&lt;unknown&gt;',
       
   247                 'function': '?',
       
   248                 'lineno': '?',
       
   249                 'context_line': '???',
       
   250             }]
       
   251 
       
   252         return frames
       
   253 
       
   254     def format_exception(self):
       
   255         """
       
   256         Return the same data as from traceback.format_exception.
       
   257         """
       
   258         import traceback
       
   259         frames = self.get_traceback_frames()
       
   260         tb = [ (f['filename'], f['lineno'], f['function'], f['context_line']) for f in frames ]
       
   261         list = ['Traceback (most recent call last):\n']
       
   262         list += traceback.format_list(tb)
       
   263         list += traceback.format_exception_only(self.exc_type, self.exc_value)
       
   264         return list
       
   265 
       
   266 
       
   267 def technical_404_response(request, exception):
       
   268     "Create a technical 404 error response. The exception should be the Http404."
       
   269     try:
       
   270         tried = exception.args[0]['tried']
       
   271     except (IndexError, TypeError, KeyError):
       
   272         tried = []
       
   273     else:
       
   274         if not tried:
       
   275             # tried exists but is an empty list. The URLconf must've been empty.
       
   276             return empty_urlconf(request)
       
   277 
       
   278     t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template')
       
   279     c = Context({
       
   280         'root_urlconf': settings.ROOT_URLCONF,
       
   281         'request_path': request.path_info[1:], # Trim leading slash
       
   282         'urlpatterns': tried,
       
   283         'reason': smart_str(exception, errors='replace'),
       
   284         'request': request,
       
   285         'settings': get_safe_settings(),
       
   286     })
       
   287     return HttpResponseNotFound(t.render(c), mimetype='text/html')
       
   288 
       
   289 def empty_urlconf(request):
       
   290     "Create an empty URLconf 404 error response."
       
   291     t = Template(EMPTY_URLCONF_TEMPLATE, name='Empty URLConf template')
       
   292     c = Context({
       
   293         'project_name': settings.SETTINGS_MODULE.split('.')[0]
       
   294     })
       
   295     return HttpResponse(t.render(c), mimetype='text/html')
       
   296 
       
   297 #
       
   298 # Templates are embedded in the file so that we know the error handler will
       
   299 # always work even if the template loader is broken.
       
   300 #
       
   301 
       
   302 TECHNICAL_500_TEMPLATE = """
       
   303 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
       
   304 <html lang="en">
       
   305 <head>
       
   306   <meta http-equiv="content-type" content="text/html; charset=utf-8">
       
   307   <meta name="robots" content="NONE,NOARCHIVE">
       
   308   <title>{{ exception_type }} at {{ request.path_info|escape }}</title>
       
   309   <style type="text/css">
       
   310     html * { padding:0; margin:0; }
       
   311     body * { padding:10px 20px; }
       
   312     body * * { padding:0; }
       
   313     body { font:small sans-serif; }
       
   314     body>div { border-bottom:1px solid #ddd; }
       
   315     h1 { font-weight:normal; }
       
   316     h2 { margin-bottom:.8em; }
       
   317     h2 span { font-size:80%; color:#666; font-weight:normal; }
       
   318     h3 { margin:1em 0 .5em 0; }
       
   319     h4 { margin:0 0 .5em 0; font-weight: normal; }
       
   320     table { border:1px solid #ccc; border-collapse: collapse; width:100%; background:white; }
       
   321     tbody td, tbody th { vertical-align:top; padding:2px 3px; }
       
   322     thead th { padding:1px 6px 1px 3px; background:#fefefe; text-align:left; font-weight:normal; font-size:11px; border:1px solid #ddd; }
       
   323     tbody th { width:12em; text-align:right; color:#666; padding-right:.5em; }
       
   324     table.vars { margin:5px 0 2px 40px; }
       
   325     table.vars td, table.req td { font-family:monospace; }
       
   326     table td.code { width:100%; }
       
   327     table td.code div { overflow:hidden; }
       
   328     table.source th { color:#666; }
       
   329     table.source td { font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
       
   330     ul.traceback { list-style-type:none; }
       
   331     ul.traceback li.frame { margin-bottom:1em; }
       
   332     div.context { margin: 10px 0; }
       
   333     div.context ol { padding-left:30px; margin:0 10px; list-style-position: inside; }
       
   334     div.context ol li { font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
       
   335     div.context ol.context-line li { color:black; background-color:#ccc; }
       
   336     div.context ol.context-line li span { float: right; }
       
   337     div.commands { margin-left: 40px; }
       
   338     div.commands a { color:black; text-decoration:none; }
       
   339     #summary { background: #ffc; }
       
   340     #summary h2 { font-weight: normal; color: #666; }
       
   341     #explanation { background:#eee; }
       
   342     #template, #template-not-exist { background:#f6f6f6; }
       
   343     #template-not-exist ul { margin: 0 0 0 20px; }
       
   344     #unicode-hint { background:#eee; }
       
   345     #traceback { background:#eee; }
       
   346     #requestinfo { background:#f6f6f6; padding-left:120px; }
       
   347     #summary table { border:none; background:transparent; }
       
   348     #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
       
   349     #requestinfo h3 { margin-bottom:-1em; }
       
   350     .error { background: #ffc; }
       
   351     .specific { color:#cc3300; font-weight:bold; }
       
   352     h2 span.commands { font-size:.7em;}
       
   353     span.commands a:link {color:#5E5694;}
       
   354     pre.exception_value { font-family: sans-serif; color: #666; font-size: 1.5em; margin: 10px 0 10px 0; }
       
   355   </style>
       
   356   <script type="text/javascript">
       
   357   //<!--
       
   358     function getElementsByClassName(oElm, strTagName, strClassName){
       
   359         // Written by Jonathan Snook, http://www.snook.ca/jon; Add-ons by Robert Nyman, http://www.robertnyman.com
       
   360         var arrElements = (strTagName == "*" && document.all)? document.all :
       
   361         oElm.getElementsByTagName(strTagName);
       
   362         var arrReturnElements = new Array();
       
   363         strClassName = strClassName.replace(/\-/g, "\\-");
       
   364         var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
       
   365         var oElement;
       
   366         for(var i=0; i<arrElements.length; i++){
       
   367             oElement = arrElements[i];
       
   368             if(oRegExp.test(oElement.className)){
       
   369                 arrReturnElements.push(oElement);
       
   370             }
       
   371         }
       
   372         return (arrReturnElements)
       
   373     }
       
   374     function hideAll(elems) {
       
   375       for (var e = 0; e < elems.length; e++) {
       
   376         elems[e].style.display = 'none';
       
   377       }
       
   378     }
       
   379     window.onload = function() {
       
   380       hideAll(getElementsByClassName(document, 'table', 'vars'));
       
   381       hideAll(getElementsByClassName(document, 'ol', 'pre-context'));
       
   382       hideAll(getElementsByClassName(document, 'ol', 'post-context'));
       
   383       hideAll(getElementsByClassName(document, 'div', 'pastebin'));
       
   384     }
       
   385     function toggle() {
       
   386       for (var i = 0; i < arguments.length; i++) {
       
   387         var e = document.getElementById(arguments[i]);
       
   388         if (e) {
       
   389           e.style.display = e.style.display == 'none' ? 'block' : 'none';
       
   390         }
       
   391       }
       
   392       return false;
       
   393     }
       
   394     function varToggle(link, id) {
       
   395       toggle('v' + id);
       
   396       var s = link.getElementsByTagName('span')[0];
       
   397       var uarr = String.fromCharCode(0x25b6);
       
   398       var darr = String.fromCharCode(0x25bc);
       
   399       s.innerHTML = s.innerHTML == uarr ? darr : uarr;
       
   400       return false;
       
   401     }
       
   402     function switchPastebinFriendly(link) {
       
   403       s1 = "Switch to copy-and-paste view";
       
   404       s2 = "Switch back to interactive view";
       
   405       link.innerHTML = link.innerHTML == s1 ? s2 : s1;
       
   406       toggle('browserTraceback', 'pastebinTraceback');
       
   407       return false;
       
   408     }
       
   409     //-->
       
   410   </script>
       
   411 </head>
       
   412 <body>
       
   413 <div id="summary">
       
   414   <h1>{{ exception_type }} at {{ request.path_info|escape }}</h1>
       
   415   <pre class="exception_value">{{ exception_value|escape }}</pre>
       
   416   <table class="meta">
       
   417     <tr>
       
   418       <th>Request Method:</th>
       
   419       <td>{{ request.META.REQUEST_METHOD }}</td>
       
   420     </tr>
       
   421     <tr>
       
   422       <th>Request URL:</th>
       
   423       <td>{{ request.build_absolute_uri|escape }}</td>
       
   424     </tr>
       
   425     <tr>
       
   426       <th>Django Version:</th>
       
   427       <td>{{ django_version_info }}</td>
       
   428     </tr>
       
   429     <tr>
       
   430       <th>Exception Type:</th>
       
   431       <td>{{ exception_type }}</td>
       
   432     </tr>
       
   433     <tr>
       
   434       <th>Exception Value:</th>
       
   435       <td><pre>{{ exception_value|escape }}</pre></td>
       
   436     </tr>
       
   437     <tr>
       
   438       <th>Exception Location:</th>
       
   439       <td>{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}</td>
       
   440     </tr>
       
   441     <tr>
       
   442       <th>Python Executable:</th>
       
   443       <td>{{ sys_executable|escape }}</td>
       
   444     </tr>
       
   445     <tr>
       
   446       <th>Python Version:</th>
       
   447       <td>{{ sys_version_info }}</td>
       
   448     </tr>
       
   449     <tr>
       
   450       <th>Python Path:</th>
       
   451       <td>{{ sys_path }}</td>
       
   452     </tr>
       
   453     <tr>
       
   454       <th>Server time:</th>
       
   455       <td>{{server_time|date:"r"}}</td>
       
   456     </tr>
       
   457   </table>
       
   458 </div>
       
   459 {% if unicode_hint %}
       
   460 <div id="unicode-hint">
       
   461     <h2>Unicode error hint</h2>
       
   462     <p>The string that could not be encoded/decoded was: <strong>{{ unicode_hint|escape }}</strong></p>
       
   463 </div>
       
   464 {% endif %}
       
   465 {% if template_does_not_exist %}
       
   466 <div id="template-not-exist">
       
   467     <h2>Template-loader postmortem</h2>
       
   468     {% if loader_debug_info %}
       
   469         <p>Django tried loading these templates, in this order:</p>
       
   470         <ul>
       
   471         {% for loader in loader_debug_info %}
       
   472             <li>Using loader <code>{{ loader.loader }}</code>:
       
   473                 <ul>{% for t in loader.templates %}<li><code>{{ t.name }}</code> (File {% if t.exists %}exists{% else %}does not exist{% endif %})</li>{% endfor %}</ul>
       
   474             </li>
       
   475         {% endfor %}
       
   476         </ul>
       
   477     {% else %}
       
   478         <p>Django couldn't find any templates because your <code>TEMPLATE_LOADERS</code> setting is empty!</p>
       
   479     {% endif %}
       
   480 </div>
       
   481 {% endif %}
       
   482 {% if template_info %}
       
   483 <div id="template">
       
   484    <h2>Template error</h2>
       
   485    <p>In template <code>{{ template_info.name }}</code>, error at line <strong>{{ template_info.line }}</strong></p>
       
   486    <h3>{{ template_info.message }}</h3>
       
   487    <table class="source{% if template_info.top %} cut-top{% endif %}{% ifnotequal template_info.bottom template_info.total %} cut-bottom{% endifnotequal %}">
       
   488    {% for source_line in template_info.source_lines %}
       
   489    {% ifequal source_line.0 template_info.line %}
       
   490        <tr class="error"><th>{{ source_line.0 }}</th>
       
   491        <td>{{ template_info.before }}<span class="specific">{{ template_info.during }}</span>{{ template_info.after }}</td></tr>
       
   492    {% else %}
       
   493       <tr><th>{{ source_line.0 }}</th>
       
   494       <td>{{ source_line.1 }}</td></tr>
       
   495    {% endifequal %}
       
   496    {% endfor %}
       
   497    </table>
       
   498 </div>
       
   499 {% endif %}
       
   500 <div id="traceback">
       
   501   <h2>Traceback <span class="commands"><a href="#" onclick="return switchPastebinFriendly(this);">Switch to copy-and-paste view</a></span></h2>
       
   502   {% autoescape off %}
       
   503   <div id="browserTraceback">
       
   504     <ul class="traceback">
       
   505       {% for frame in frames %}
       
   506         <li class="frame">
       
   507           <code>{{ frame.filename|escape }}</code> in <code>{{ frame.function|escape }}</code>
       
   508 
       
   509           {% if frame.context_line %}
       
   510             <div class="context" id="c{{ frame.id }}">
       
   511               {% if frame.pre_context %}
       
   512                 <ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
       
   513               {% endif %}
       
   514               <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line|escape }} <span>...</span></li></ol>
       
   515               {% if frame.post_context %}
       
   516                 <ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
       
   517               {% endif %}
       
   518             </div>
       
   519           {% endif %}
       
   520 
       
   521           {% if frame.vars %}
       
   522             <div class="commands">
       
   523                 <a href="#" onclick="return varToggle(this, '{{ frame.id }}')"><span>&#x25b6;</span> Local vars</a>
       
   524             </div>
       
   525             <table class="vars" id="v{{ frame.id }}">
       
   526               <thead>
       
   527                 <tr>
       
   528                   <th>Variable</th>
       
   529                   <th>Value</th>
       
   530                 </tr>
       
   531               </thead>
       
   532               <tbody>
       
   533                 {% for var in frame.vars|dictsort:"0" %}
       
   534                   <tr>
       
   535                     <td>{{ var.0|escape }}</td>
       
   536                     <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
       
   537                   </tr>
       
   538                 {% endfor %}
       
   539               </tbody>
       
   540             </table>
       
   541           {% endif %}
       
   542         </li>
       
   543       {% endfor %}
       
   544     </ul>
       
   545   </div>
       
   546   {% endautoescape %}
       
   547   <form action="http://dpaste.com/" name="pasteform" id="pasteform" method="post">
       
   548   <div id="pastebinTraceback" class="pastebin">
       
   549     <input type="hidden" name="language" value="PythonConsole">
       
   550     <input type="hidden" name="title" value="{{ exception_type|escape }} at {{ request.path_info|escape }}">
       
   551     <input type="hidden" name="source" value="Django Dpaste Agent">
       
   552     <input type="hidden" name="poster" value="Django">
       
   553     <textarea name="content" id="traceback_area" cols="140" rows="25">
       
   554 Environment:
       
   555 
       
   556 Request Method: {{ request.META.REQUEST_METHOD }}
       
   557 Request URL: {{ request.build_absolute_uri|escape }}
       
   558 Django Version: {{ django_version_info }}
       
   559 Python Version: {{ sys_version_info }}
       
   560 Installed Applications:
       
   561 {{ settings.INSTALLED_APPS|pprint }}
       
   562 Installed Middleware:
       
   563 {{ settings.MIDDLEWARE_CLASSES|pprint }}
       
   564 
       
   565 {% if template_does_not_exist %}Template Loader Error:
       
   566 {% if loader_debug_info %}Django tried loading these templates, in this order:
       
   567 {% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
       
   568 {% for t in loader.templates %}{{ t.name }} (File {% if t.exists %}exists{% else %}does not exist{% endif %})
       
   569 {% endfor %}{% endfor %}
       
   570 {% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!
       
   571 {% endif %}
       
   572 {% endif %}{% if template_info %}
       
   573 Template error:
       
   574 In template {{ template_info.name }}, error at line {{ template_info.line }}
       
   575    {{ template_info.message }}{% for source_line in template_info.source_lines %}{% ifequal source_line.0 template_info.line %}
       
   576    {{ source_line.0 }} : {{ template_info.before }} {{ template_info.during }} {{ template_info.after }}
       
   577 {% else %}
       
   578    {{ source_line.0 }} : {{ source_line.1 }}
       
   579 {% endifequal %}{% endfor %}{% endif %}
       
   580 Traceback:
       
   581 {% for frame in frames %}File "{{ frame.filename|escape }}" in {{ frame.function|escape }}
       
   582 {% if frame.context_line %}  {{ frame.lineno }}. {{ frame.context_line|escape }}{% endif %}
       
   583 {% endfor %}
       
   584 Exception Type: {{ exception_type|escape }} at {{ request.path_info|escape }}
       
   585 Exception Value: {{ exception_value|escape }}
       
   586 </textarea>
       
   587   <br><br>
       
   588   <input type="submit" value="Share this traceback on a public Web site">
       
   589   </div>
       
   590 </form>
       
   591 </div>
       
   592 
       
   593 <div id="requestinfo">
       
   594   <h2>Request information</h2>
       
   595 
       
   596   <h3 id="get-info">GET</h3>
       
   597   {% if request.GET %}
       
   598     <table class="req">
       
   599       <thead>
       
   600         <tr>
       
   601           <th>Variable</th>
       
   602           <th>Value</th>
       
   603         </tr>
       
   604       </thead>
       
   605       <tbody>
       
   606         {% for var in request.GET.items %}
       
   607           <tr>
       
   608             <td>{{ var.0 }}</td>
       
   609             <td class="code"><div>{{ var.1|pprint }}</div></td>
       
   610           </tr>
       
   611         {% endfor %}
       
   612       </tbody>
       
   613     </table>
       
   614   {% else %}
       
   615     <p>No GET data</p>
       
   616   {% endif %}
       
   617 
       
   618   <h3 id="post-info">POST</h3>
       
   619   {% if request.POST %}
       
   620     <table class="req">
       
   621       <thead>
       
   622         <tr>
       
   623           <th>Variable</th>
       
   624           <th>Value</th>
       
   625         </tr>
       
   626       </thead>
       
   627       <tbody>
       
   628         {% for var in request.POST.items %}
       
   629           <tr>
       
   630             <td>{{ var.0 }}</td>
       
   631             <td class="code"><div>{{ var.1|pprint }}</div></td>
       
   632           </tr>
       
   633         {% endfor %}
       
   634       </tbody>
       
   635     </table>
       
   636   {% else %}
       
   637     <p>No POST data</p>
       
   638   {% endif %}
       
   639   <h3 id="files-info">FILES</h3>
       
   640   {% if request.FILES %}
       
   641     <table class="req">
       
   642         <thead>
       
   643             <tr>
       
   644                 <th>Variable</th>
       
   645                 <th>Value</th>
       
   646             </tr>
       
   647         </thead>
       
   648         <tbody>
       
   649             {% for var in request.FILES.items %}
       
   650                 <tr>
       
   651                     <td>{{ var.0 }}</td>
       
   652                     <td class="code"><div>{{ var.1|pprint }}</div></td>
       
   653                 </tr>
       
   654             {% endfor %}
       
   655         </tbody>
       
   656     </table>
       
   657   {% else %}
       
   658     <p>No FILES data</p>
       
   659   {% endif %}
       
   660 
       
   661 
       
   662   <h3 id="cookie-info">COOKIES</h3>
       
   663   {% if request.COOKIES %}
       
   664     <table class="req">
       
   665       <thead>
       
   666         <tr>
       
   667           <th>Variable</th>
       
   668           <th>Value</th>
       
   669         </tr>
       
   670       </thead>
       
   671       <tbody>
       
   672         {% for var in request.COOKIES.items %}
       
   673           <tr>
       
   674             <td>{{ var.0 }}</td>
       
   675             <td class="code"><div>{{ var.1|pprint }}</div></td>
       
   676           </tr>
       
   677         {% endfor %}
       
   678       </tbody>
       
   679     </table>
       
   680   {% else %}
       
   681     <p>No cookie data</p>
       
   682   {% endif %}
       
   683 
       
   684   <h3 id="meta-info">META</h3>
       
   685   <table class="req">
       
   686     <thead>
       
   687       <tr>
       
   688         <th>Variable</th>
       
   689         <th>Value</th>
       
   690       </tr>
       
   691     </thead>
       
   692     <tbody>
       
   693       {% for var in request.META.items|dictsort:"0" %}
       
   694         <tr>
       
   695           <td>{{ var.0 }}</td>
       
   696           <td class="code"><div>{{ var.1|pprint }}</div></td>
       
   697         </tr>
       
   698       {% endfor %}
       
   699     </tbody>
       
   700   </table>
       
   701 
       
   702   <h3 id="settings-info">Settings</h3>
       
   703   <h4>Using settings module <code>{{ settings.SETTINGS_MODULE }}</code></h4>
       
   704   <table class="req">
       
   705     <thead>
       
   706       <tr>
       
   707         <th>Setting</th>
       
   708         <th>Value</th>
       
   709       </tr>
       
   710     </thead>
       
   711     <tbody>
       
   712       {% for var in settings.items|dictsort:"0" %}
       
   713         <tr>
       
   714           <td>{{ var.0 }}</td>
       
   715           <td class="code"><div>{{ var.1|pprint }}</div></td>
       
   716         </tr>
       
   717       {% endfor %}
       
   718     </tbody>
       
   719   </table>
       
   720 
       
   721 </div>
       
   722 
       
   723 <div id="explanation">
       
   724   <p>
       
   725     You're seeing this error because you have <code>DEBUG = True</code> in your
       
   726     Django settings file. Change that to <code>False</code>, and Django will
       
   727     display a standard 500 page.
       
   728   </p>
       
   729 </div>
       
   730 </body>
       
   731 </html>
       
   732 """
       
   733 
       
   734 TECHNICAL_404_TEMPLATE = """
       
   735 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
       
   736 <html lang="en">
       
   737 <head>
       
   738   <meta http-equiv="content-type" content="text/html; charset=utf-8">
       
   739   <title>Page not found at {{ request.path_info|escape }}</title>
       
   740   <meta name="robots" content="NONE,NOARCHIVE">
       
   741   <style type="text/css">
       
   742     html * { padding:0; margin:0; }
       
   743     body * { padding:10px 20px; }
       
   744     body * * { padding:0; }
       
   745     body { font:small sans-serif; background:#eee; }
       
   746     body>div { border-bottom:1px solid #ddd; }
       
   747     h1 { font-weight:normal; margin-bottom:.4em; }
       
   748     h1 span { font-size:60%; color:#666; font-weight:normal; }
       
   749     table { border:none; border-collapse: collapse; width:100%; }
       
   750     td, th { vertical-align:top; padding:2px 3px; }
       
   751     th { width:12em; text-align:right; color:#666; padding-right:.5em; }
       
   752     #info { background:#f6f6f6; }
       
   753     #info ol { margin: 0.5em 4em; }
       
   754     #info ol li { font-family: monospace; }
       
   755     #summary { background: #ffc; }
       
   756     #explanation { background:#eee; border-bottom: 0px none; }
       
   757   </style>
       
   758 </head>
       
   759 <body>
       
   760   <div id="summary">
       
   761     <h1>Page not found <span>(404)</span></h1>
       
   762     <table class="meta">
       
   763       <tr>
       
   764         <th>Request Method:</th>
       
   765         <td>{{ request.META.REQUEST_METHOD }}</td>
       
   766       </tr>
       
   767       <tr>
       
   768         <th>Request URL:</th>
       
   769       <td>{{ request.build_absolute_uri|escape }}</td>
       
   770       </tr>
       
   771     </table>
       
   772   </div>
       
   773   <div id="info">
       
   774     {% if urlpatterns %}
       
   775       <p>
       
   776       Using the URLconf defined in <code>{{ settings.ROOT_URLCONF }}</code>,
       
   777       Django tried these URL patterns, in this order:
       
   778       </p>
       
   779       <ol>
       
   780         {% for pattern in urlpatterns %}
       
   781           <li>{{ pattern }}</li>
       
   782         {% endfor %}
       
   783       </ol>
       
   784       <p>The current URL, <code>{{ request_path|escape }}</code>, didn't match any of these.</p>
       
   785     {% else %}
       
   786       <p>{{ reason }}</p>
       
   787     {% endif %}
       
   788   </div>
       
   789 
       
   790   <div id="explanation">
       
   791     <p>
       
   792       You're seeing this error because you have <code>DEBUG = True</code> in
       
   793       your Django settings file. Change that to <code>False</code>, and Django
       
   794       will display a standard 404 page.
       
   795     </p>
       
   796   </div>
       
   797 </body>
       
   798 </html>
       
   799 """
       
   800 
       
   801 EMPTY_URLCONF_TEMPLATE = """
       
   802 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
       
   803 <html lang="en"><head>
       
   804   <meta http-equiv="content-type" content="text/html; charset=utf-8">
       
   805   <meta name="robots" content="NONE,NOARCHIVE"><title>Welcome to Django</title>
       
   806   <style type="text/css">
       
   807     html * { padding:0; margin:0; }
       
   808     body * { padding:10px 20px; }
       
   809     body * * { padding:0; }
       
   810     body { font:small sans-serif; }
       
   811     body>div { border-bottom:1px solid #ddd; }
       
   812     h1 { font-weight:normal; }
       
   813     h2 { margin-bottom:.8em; }
       
   814     h2 span { font-size:80%; color:#666; font-weight:normal; }
       
   815     h3 { margin:1em 0 .5em 0; }
       
   816     h4 { margin:0 0 .5em 0; font-weight: normal; }
       
   817     table { border:1px solid #ccc; border-collapse: collapse; width:100%; background:white; }
       
   818     tbody td, tbody th { vertical-align:top; padding:2px 3px; }
       
   819     thead th { padding:1px 6px 1px 3px; background:#fefefe; text-align:left; font-weight:normal; font-size:11px; border:1px solid #ddd; }
       
   820     tbody th { width:12em; text-align:right; color:#666; padding-right:.5em; }
       
   821     ul { margin-left: 2em; margin-top: 1em; }
       
   822     #summary { background: #e0ebff; }
       
   823     #summary h2 { font-weight: normal; color: #666; }
       
   824     #explanation { background:#eee; }
       
   825     #instructions { background:#f6f6f6; }
       
   826     #summary table { border:none; background:transparent; }
       
   827   </style>
       
   828 </head>
       
   829 
       
   830 <body>
       
   831 <div id="summary">
       
   832   <h1>It worked!</h1>
       
   833   <h2>Congratulations on your first Django-powered page.</h2>
       
   834 </div>
       
   835 
       
   836 <div id="instructions">
       
   837   <p>Of course, you haven't actually done any work yet. Here's what to do next:</p>
       
   838   <ul>
       
   839     <li>If you plan to use a database, edit the <code>DATABASES</code> setting in <code>{{ project_name }}/settings.py</code>.</li>
       
   840     <li>Start your first app by running <code>python {{ project_name }}/manage.py startapp [appname]</code>.</li>
       
   841   </ul>
       
   842 </div>
       
   843 
       
   844 <div id="explanation">
       
   845   <p>
       
   846     You're seeing this message because you have <code>DEBUG = True</code> in your
       
   847     Django settings file and you haven't configured any URLs. Get to work!
       
   848   </p>
       
   849 </div>
       
   850 </body></html>
       
   851 """