Prepare for callbacks that return more than one menu
This paves the way for callbacks that dynamically construct their
menu based on in-db content, such as Programs and Documents.
Patch by: Sverre Rabbelier
import osimport reimport sysimport datetimefrom django.conf import settingsfrom django.template import Template, Context, TemplateDoesNotExistfrom django.utils.html import escapefrom django.http import HttpResponse, HttpResponseServerError, HttpResponseNotFoundfrom django.utils.encoding import smart_unicode, smart_strHIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')def linebreak_iter(template_source): yield 0 p = template_source.find('\n') while p >= 0: yield p+1 p = template_source.find('\n', p+1) yield len(template_source) + 1def get_safe_settings(): "Returns a dictionary of the settings module, with sensitive settings blurred out." settings_dict = {} for k in dir(settings): if k.isupper(): if HIDDEN_SETTINGS.search(k): settings_dict[k] = '********************' else: settings_dict[k] = getattr(settings, k) return settings_dictdef 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. """ reporter = ExceptionReporter(request, exc_type, exc_value, tb) html = reporter.get_traceback_html() return HttpResponseServerError(html, mimetype='text/html')class ExceptionReporter: """ A class to organize and coordinate reporting on exceptions. """ def __init__(self, request, exc_type, exc_value, tb): self.request = request self.exc_type = exc_type self.exc_value = exc_value self.tb = tb self.template_info = None self.template_does_not_exist = False self.loader_debug_info = None # Handle deprecated string exceptions if isinstance(self.exc_type, basestring): self.exc_value = Exception('Deprecated String Exception: %r' % self.exc_type) self.exc_type = type(self.exc_value) def get_traceback_html(self): "Return HTML code for traceback." if issubclass(self.exc_type, TemplateDoesNotExist): from django.template.loader import template_source_loaders self.template_does_not_exist = True self.loader_debug_info = [] for loader in template_source_loaders: try: source_list_func = getattr(__import__(loader.__module__, {}, {}, ['get_template_sources']), 'get_template_sources') # NOTE: This assumes exc_value is the name of the template that # the loader attempted to load. template_list = [{'name': t, 'exists': os.path.exists(t)} \ for t in source_list_func(str(self.exc_value))] except (ImportError, AttributeError): template_list = [] self.loader_debug_info.append({ 'loader': loader.__module__ + '.' + loader.__name__, 'templates': template_list, }) if settings.TEMPLATE_DEBUG and hasattr(self.exc_value, 'source'): self.get_template_exception_info() frames = self.get_traceback_frames() unicode_hint = '' if issubclass(self.exc_type, UnicodeError): start = getattr(self.exc_value, 'start', None) end = getattr(self.exc_value, 'end', None) if start is not None and end is not None: unicode_str = self.exc_value.args[1] unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace') from django import get_version t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') c = Context({ 'exception_type': self.exc_type.__name__, 'exception_value': smart_unicode(self.exc_value, errors='replace'), 'unicode_hint': unicode_hint, 'frames': frames, 'lastframe': frames[-1], 'request': self.request, 'request_protocol': self.request.is_secure() and "https" or "http", 'settings': get_safe_settings(), 'sys_executable': sys.executable, 'sys_version_info': '%d.%d.%d' % sys.version_info[0:3], 'server_time': datetime.datetime.now(), 'django_version_info': get_version(), 'sys_path' : sys.path, 'template_info': self.template_info, 'template_does_not_exist': self.template_does_not_exist, 'loader_debug_info': self.loader_debug_info, }) return t.render(c) def get_template_exception_info(self): origin, (start, end) = self.exc_value.source template_source = origin.reload() context_lines = 10 line = 0 upto = 0 source_lines = [] before = during = after = "" for num, next in enumerate(linebreak_iter(template_source)): if start >= upto and end <= next: line = num before = escape(template_source[upto:start]) during = escape(template_source[start:end]) after = escape(template_source[end:next]) source_lines.append( (num, escape(template_source[upto:next])) ) upto = next total = len(source_lines) top = max(1, line - context_lines) bottom = min(total, line + 1 + context_lines) self.template_info = { 'message': self.exc_value.args[0], 'source_lines': source_lines[top:bottom], 'before': before, 'during': during, 'after': after, 'top': top, 'bottom': bottom, 'total': total, 'line': line, 'name': origin.name, } def _get_lines_from_file(self, filename, lineno, context_lines, loader=None, module_name=None): """ Returns context_lines before and after lineno from file. Returns (pre_context_lineno, pre_context, context_line, post_context). """ source = None if loader is not None and hasattr(loader, "get_source"): source = loader.get_source(module_name) if source is not None: source = source.splitlines() if source is None: try: f = open(filename) try: source = f.readlines() finally: f.close() except (OSError, IOError): pass if source is None: return None, [], None, [] encoding = 'ascii' for line in source[:2]: # File coding may be specified. Match pattern from PEP-263 # (http://www.python.org/dev/peps/pep-0263/) match = re.search(r'coding[:=]\s*([-\w.]+)', line) if match: encoding = match.group(1) break source = [unicode(sline, encoding, 'replace') for sline in source] 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 def get_traceback_frames(self): frames = [] tb = self.tb while tb is not None: # support for __traceback_hide__ which is used by a few libraries # to hide internal frames. if tb.tb_frame.f_locals.get('__traceback_hide__'): tb = tb.tb_next continue filename = tb.tb_frame.f_code.co_filename function = tb.tb_frame.f_code.co_name lineno = tb.tb_lineno - 1 loader = tb.tb_frame.f_globals.get('__loader__') module_name = tb.tb_frame.f_globals.get('__name__') pre_context_lineno, pre_context, context_line, post_context = self._get_lines_from_file(filename, lineno, 7, loader, module_name) if pre_context_lineno is not None: frames.append({ 'tb': tb, 'filename': filename, 'function': function, 'lineno': lineno + 1, 'vars': tb.tb_frame.f_locals.items(), 'id': id(tb), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, 'pre_context_lineno': pre_context_lineno + 1, }) tb = tb.tb_next if not frames: frames = [{ 'filename': '<unknown>', 'function': '?', 'lineno': '?', 'context_line': '???', }] return frames def format_exception(self): """ Return the same data as from traceback.format_exception. """ import traceback frames = self.get_traceback_frames() tb = [ (f['filename'], f['lineno'], f['function'], f['context_line']) for f in frames ] list = ['Traceback (most recent call last):\n'] list += traceback.format_list(tb) list += traceback.format_exception_only(self.exc_type, self.exc_value) return listdef technical_404_response(request, exception): "Create a technical 404 error response. The exception should be the Http404." try: tried = exception.args[0]['tried'] except (IndexError, TypeError): tried = [] else: if not tried: # tried exists but is an empty list. The URLconf must've been empty. return empty_urlconf(request) t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') c = Context({ 'root_urlconf': settings.ROOT_URLCONF, 'request_path': request.path_info[1:], # Trim leading slash 'urlpatterns': tried, 'reason': smart_str(exception, errors='replace'), 'request': request, 'request_protocol': request.is_secure() and "https" or "http", 'settings': get_safe_settings(), }) return HttpResponseNotFound(t.render(c), mimetype='text/html')def empty_urlconf(request): "Create an empty URLconf 404 error response." t = Template(EMPTY_URLCONF_TEMPLATE, name='Empty URLConf template') c = Context({ 'project_name': settings.SETTINGS_MODULE.split('.')[0] }) return HttpResponse(t.render(c), mimetype='text/html')## 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"> <meta name="robots" content="NONE,NOARCHIVE"> <title>{{ exception_type }} at {{ request.path_info|escape }}</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; } table.source th { color:#666; } table.source td { font-family:monospace; white-space:pre; border-bottom:1px solid #eee; } 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; cursor:pointer; } div.context ol.context-line li { color:black; background-color:#ccc; } div.context ol.context-line li span { float: right; } 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; } #template, #template-not-exist { background:#f6f6f6; } #template-not-exist ul { margin: 0 0 0 20px; } #unicode-hint { 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; } .error { background: #ffc; } .specific { color:#cc3300; font-weight:bold; } h2 span.commands { font-size:.7em;} span.commands a:link {color:#5E5694;} pre.exception_value { font-family: sans-serif; color: #666; font-size: 1.5em; margin: 10px 0 10px 0; } </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')); hideAll(getElementsByClassName(document, 'div', 'pastebin')); } 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(0x25b6); var darr = String.fromCharCode(0x25bc); s.innerHTML = s.innerHTML == uarr ? darr : uarr; return false; } function switchPastebinFriendly(link) { s1 = "Switch to copy-and-paste view"; s2 = "Switch back to interactive view"; link.innerHTML = link.innerHTML == s1 ? s2 : s1; toggle('browserTraceback', 'pastebinTraceback'); return false; } //--> </script></head><body><div id="summary"> <h1>{{ exception_type }} at {{ request.path_info|escape }}</h1> <pre class="exception_value">{{ exception_value|escape }}</pre> <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_info|escape }}</td> </tr> <tr> <th>Exception Type:</th> <td>{{ exception_type }}</td> </tr> <tr> <th>Exception Value:</th> <td><pre>{{ exception_value|escape }}<pre></td> </tr> <tr> <th>Exception Location:</th> <td>{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}</td> </tr> <tr> <th>Python Executable:</th> <td>{{ sys_executable|escape }}</td> </tr> <tr> <th>Python Version:</th> <td>{{ sys_version_info }}</td> </tr> <tr> <th>Python Path:</th> <td>{{ sys_path }}</td> </tr> <tr> <th>Server time:</th> <td>{{server_time|date:"r"}}</td> </tr> </table></div>{% if unicode_hint %}<div id="unicode-hint"> <h2>Unicode error hint</h2> <p>The string that could not be encoded/decoded was: <strong>{{ unicode_hint|escape }}</strong></p></div>{% endif %}{% if template_does_not_exist %}<div id="template-not-exist"> <h2>Template-loader postmortem</h2> {% if loader_debug_info %} <p>Django tried loading these templates, in this order:</p> <ul> {% for loader in loader_debug_info %} <li>Using loader <code>{{ loader.loader }}</code>: <ul>{% for t in loader.templates %}<li><code>{{ t.name }}</code> (File {% if t.exists %}exists{% else %}does not exist{% endif %})</li>{% endfor %}</ul> </li> {% endfor %} </ul> {% else %} <p>Django couldn't find any templates because your <code>TEMPLATE_LOADERS</code> setting is empty!</p> {% endif %}</div>{% endif %}{% if template_info %}<div id="template"> <h2>Template error</h2> <p>In template <code>{{ template_info.name }}</code>, error at line <strong>{{ template_info.line }}</strong></p> <h3>{{ template_info.message }}</h3> <table class="source{% if template_info.top %} cut-top{% endif %}{% ifnotequal template_info.bottom template_info.total %} cut-bottom{% endifnotequal %}"> {% for source_line in template_info.source_lines %} {% ifequal source_line.0 template_info.line %} <tr class="error"><th>{{ 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> <td>{{ source_line.1 }}</td></tr> {% endifequal %} {% endfor %} </table></div>{% endif %}<div id="traceback"> <h2>Traceback <span class="commands"><a href="#" onclick="return switchPastebinFriendly(this);">Switch to copy-and-paste view</a></span></h2> {% autoescape off %} <div id="browserTraceback"> <ul class="traceback"> {% for frame in frames %} <li class="frame"> <code>{{ frame.filename|escape }}</code> in <code>{{ frame.function|escape }}</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 onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ 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 }} <span>...</span></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 onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol> {% endif %} </div> {% endif %} {% if frame.vars %} <div class="commands"> <a href="#" onclick="return varToggle(this, '{{ frame.id }}')"><span>▶</span> Local vars</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|dictsort:"0" %} <tr> <td>{{ var.0|escape }}</td> <td class="code"><div>{{ var.1|pprint|escape }}</div></td> </tr> {% endfor %} </tbody> </table> {% endif %} </li> {% endfor %} </ul> </div> {% endautoescape %} <form action="http://dpaste.com/" name="pasteform" id="pasteform" method="post"> <div id="pastebinTraceback" class="pastebin"> <input type="hidden" name="language" value="PythonConsole"> <input type="hidden" name="title" value="{{ exception_type|escape }} at {{ request.path_info|escape }}"> <input type="hidden" name="source" value="Django Dpaste Agent"> <input type="hidden" name="poster" value="Django"> <textarea name="content" id="traceback_area" cols="140" rows="25">Environment:Request Method: {{ request.META.REQUEST_METHOD }}Request URL: {{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path_info|escape }}Django Version: {{ django_version_info }}Python Version: {{ sys_version_info }}Installed Applications:{{ settings.INSTALLED_APPS|pprint }}Installed Middleware:{{ settings.MIDDLEWARE_CLASSES|pprint }}{% if template_does_not_exist %}Template Loader Error:{% if loader_debug_info %}Django tried loading these templates, in this order:{% for loader in loader_debug_info %}Using loader {{ loader.loader }}:{% for t in loader.templates %}{{ t.name }} (File {% if t.exists %}exists{% else %}does not exist{% endif %}){% endfor %}{% endfor %}{% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!{% endif %}{% endif %}{% if template_info %}Template error:In template {{ template_info.name }}, error at line {{ template_info.line }} {{ template_info.message }}{% for source_line in template_info.source_lines %}{% ifequal source_line.0 template_info.line %} {{ source_line.0 }} : {{ template_info.before }} {{ template_info.during }} {{ template_info.after }}{% else %} {{ source_line.0 }} : {{ source_line.1 }}{% endifequal %}{% endfor %}{% endif %}Traceback:{% for frame in frames %}File "{{ frame.filename|escape }}" in {{ frame.function|escape }}{% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line|escape }}{% endif %}{% endfor %}Exception Type: {{ exception_type|escape }} at {{ request.path_info|escape }}Exception Value: {{ exception_value|escape }}</textarea> <br><br> <input type="submit" value="Share this traceback on a public Web site"> </div></form></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 }}</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 }}</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 }}</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 }}</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 }}</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_info|escape }}</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_info|escape }}</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 }}</li> {% endfor %} </ol> <p>The current URL, <code>{{ request_path|escape }}</code>, didn't match any of these.</p> {% else %} <p>{{ reason }}</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>"""EMPTY_URLCONF_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"> <meta name="robots" content="NONE,NOARCHIVE"><title>Welcome to Django</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; } ul { margin-left: 2em; margin-top: 1em; } #summary { background: #e0ebff; } #summary h2 { font-weight: normal; color: #666; } #explanation { background:#eee; } #instructions { background:#f6f6f6; } #summary table { border:none; background:transparent; } </style></head><body><div id="summary"> <h1>It worked!</h1> <h2>Congratulations on your first Django-powered page.</h2></div><div id="instructions"> <p>Of course, you haven't actually done any work yet. Here's what to do next:</p> <ul> <li>If you plan to use a database, edit the <code>DATABASE_*</code> settings in <code>{{ project_name }}/settings.py</code>.</li> <li>Start your first app by running <code>python {{ project_name }}/manage.py startapp [appname]</code>.</li> </ul></div><div id="explanation"> <p> You're seeing this message because you have <code>DEBUG = True</code> in your Django settings file and you haven't configured any URLs. Get to work! </p></div></body></html>"""