diff options
author | ttt | 2017-05-13 00:29:47 +0530 |
---|---|---|
committer | ttt | 2017-05-13 00:29:47 +0530 |
commit | abf599be33b383a6a5baf9493093b2126a622ac8 (patch) | |
tree | 4c5ab6e0d935d5e65fabcf0258e4a00dd20a5afa /lib/python2.7/site-packages/django/views | |
download | SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.tar.gz SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.tar.bz2 SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.zip |
added all server files
Diffstat (limited to 'lib/python2.7/site-packages/django/views')
20 files changed, 3916 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/views/__init__.py b/lib/python2.7/site-packages/django/views/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/__init__.py diff --git a/lib/python2.7/site-packages/django/views/csrf.py b/lib/python2.7/site-packages/django/views/csrf.py new file mode 100644 index 0000000..c95d19d --- /dev/null +++ b/lib/python2.7/site-packages/django/views/csrf.py @@ -0,0 +1,104 @@ +from django.http import HttpResponseForbidden +from django.template import Context, Template +from django.conf import settings + +# We include the template inline since we need to be able to reliably display +# this error message, especially for the sake of developers, and there isn't any +# other way of making it available independent of what is in the settings file. + +CSRF_FAILURE_TEMPLATE = """ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <meta name="robots" content="NONE,NOARCHIVE"> + <title>403 Forbidden</title> + <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; } + #info { background:#f6f6f6; } + #info ul { margin: 0.5em 4em; } + #info p, #summary p { padding-top:10px; } + #summary { background: #ffc; } + #explanation { background:#eee; border-bottom: 0px none; } + </style> +</head> +<body> +<div id="summary"> + <h1>Forbidden <span>(403)</span></h1> + <p>CSRF verification failed. Request aborted.</p> +{% if no_referer %} + <p>You are seeing this message because this HTTPS site requires a 'Referer + header' to be sent by your Web browser, but none was sent. This header is + required for security reasons, to ensure that your browser is not being + hijacked by third parties.</p> + + <p>If you have configured your browser to disable 'Referer' headers, please + re-enable them, at least for this site, or for HTTPS connections, or for + 'same-origin' requests.</p> +{% endif %} +</div> +{% if DEBUG %} +<div id="info"> + <h2>Help</h2> + {% if reason %} + <p>Reason given for failure:</p> + <pre> + {{ reason }} + </pre> + {% endif %} + + <p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when + <a + href='http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ref-contrib-csrf'>Django's + CSRF mechanism</a> has not been used correctly. For POST forms, you need to + ensure:</p> + + <ul> + <li>Your browser is accepting cookies.</li> + + <li>The view function uses <a + href='http://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext'><code>RequestContext</code></a> + for the template, instead of <code>Context</code>.</li> + + <li>In the template, there is a <code>{% templatetag openblock %} csrf_token + {% templatetag closeblock %}</code> template tag inside each POST form that + targets an internal URL.</li> + + <li>If you are not using <code>CsrfViewMiddleware</code>, then you must use + <code>csrf_protect</code> on any views that use the <code>csrf_token</code> + template tag, as well as those that accept the POST data.</li> + + </ul> + + <p>You're seeing the help section of this page because you have <code>DEBUG = + True</code> in your Django settings file. Change that to <code>False</code>, + and only the initial error message will be displayed. </p> + + <p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p> +</div> +{% else %} +<div id="explanation"> + <p><small>More information is available with DEBUG=True.</small></p> +</div> +{% endif %} +</body> +</html> +""" + +def csrf_failure(request, reason=""): + """ + Default view used when request fails CSRF protection + """ + from django.middleware.csrf import REASON_NO_REFERER + t = Template(CSRF_FAILURE_TEMPLATE) + c = Context({'DEBUG': settings.DEBUG, + 'reason': reason, + 'no_referer': reason == REASON_NO_REFERER + }) + return HttpResponseForbidden(t.render(c), content_type='text/html') diff --git a/lib/python2.7/site-packages/django/views/debug.py b/lib/python2.7/site-packages/django/views/debug.py new file mode 100644 index 0000000..a610c55 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/debug.py @@ -0,0 +1,1150 @@ +from __future__ import unicode_literals + +import datetime +import os +import re +import sys +import types + +from django.conf import settings +from django.http import (HttpResponse, HttpResponseServerError, + HttpResponseNotFound, HttpRequest, build_request_repr) +from django.template import Template, Context, TemplateDoesNotExist +from django.template.defaultfilters import force_escape, pprint +from django.utils.datastructures import MultiValueDict +from django.utils.html import escape +from django.utils.encoding import force_bytes, smart_text +from django.utils.module_loading import import_by_path +from django.utils import six + +HIDDEN_SETTINGS = re.compile('API|TOKEN|KEY|SECRET|PASS|PROFANITIES_LIST|SIGNATURE') + +CLEANSED_SUBSTITUTE = '********************' + +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) + 1 + +def cleanse_setting(key, value): + """Cleanse an individual setting key/value of sensitive content. + + If the value is a dictionary, recursively cleanse the keys in + that dictionary. + """ + try: + if HIDDEN_SETTINGS.search(key): + cleansed = CLEANSED_SUBSTITUTE + else: + if isinstance(value, dict): + cleansed = dict((k, cleanse_setting(k, v)) for k,v in value.items()) + else: + cleansed = value + except TypeError: + # If the key isn't regex-able, just return as-is. + cleansed = value + return cleansed + +def 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(): + settings_dict[k] = cleanse_setting(k, getattr(settings, k)) + return settings_dict + +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. + """ + reporter = ExceptionReporter(request, exc_type, exc_value, tb) + if request.is_ajax(): + text = reporter.get_traceback_text() + return HttpResponseServerError(text, content_type='text/plain') + else: + html = reporter.get_traceback_html() + return HttpResponseServerError(html, content_type='text/html') + +# Cache for the default exception reporter filter instance. +default_exception_reporter_filter = None + +def get_exception_reporter_filter(request): + global default_exception_reporter_filter + if default_exception_reporter_filter is None: + # Load the default filter for the first time and cache it. + default_exception_reporter_filter = import_by_path( + settings.DEFAULT_EXCEPTION_REPORTER_FILTER)() + if request: + return getattr(request, 'exception_reporter_filter', default_exception_reporter_filter) + else: + return default_exception_reporter_filter + +class ExceptionReporterFilter(object): + """ + Base for all exception reporter filter classes. All overridable hooks + contain lenient default behaviors. + """ + + def get_request_repr(self, request): + if request is None: + return repr(None) + else: + return build_request_repr(request, POST_override=self.get_post_parameters(request)) + + def get_post_parameters(self, request): + if request is None: + return {} + else: + return request.POST + + def get_traceback_frame_variables(self, request, tb_frame): + return list(six.iteritems(tb_frame.f_locals)) + +class SafeExceptionReporterFilter(ExceptionReporterFilter): + """ + Use annotations made by the sensitive_post_parameters and + sensitive_variables decorators to filter out sensitive information. + """ + + def is_active(self, request): + """ + This filter is to add safety in production environments (i.e. DEBUG + is False). If DEBUG is True then your site is not safe anyway. + This hook is provided as a convenience to easily activate or + deactivate the filter on a per request basis. + """ + return settings.DEBUG is False + + def get_cleansed_multivaluedict(self, request, multivaluedict): + """ + Replaces the keys in a MultiValueDict marked as sensitive with stars. + This mitigates leaking sensitive POST parameters if something like + request.POST['nonexistent_key'] throws an exception (#21098). + """ + sensitive_post_parameters = getattr(request, 'sensitive_post_parameters', []) + if self.is_active(request) and sensitive_post_parameters: + multivaluedict = multivaluedict.copy() + for param in sensitive_post_parameters: + if param in multivaluedict: + multivaluedict[param] = CLEANSED_SUBSTITUTE + return multivaluedict + + def get_post_parameters(self, request): + """ + Replaces the values of POST parameters marked as sensitive with + stars (*********). + """ + if request is None: + return {} + else: + sensitive_post_parameters = getattr(request, 'sensitive_post_parameters', []) + if self.is_active(request) and sensitive_post_parameters: + cleansed = request.POST.copy() + if sensitive_post_parameters == '__ALL__': + # Cleanse all parameters. + for k, v in cleansed.items(): + cleansed[k] = CLEANSED_SUBSTITUTE + return cleansed + else: + # Cleanse only the specified parameters. + for param in sensitive_post_parameters: + if param in cleansed: + cleansed[param] = CLEANSED_SUBSTITUTE + return cleansed + else: + return request.POST + + def cleanse_special_types(self, request, value): + if isinstance(value, HttpRequest): + # Cleanse the request's POST parameters. + value = self.get_request_repr(value) + elif isinstance(value, MultiValueDict): + # Cleanse MultiValueDicts (request.POST is the one we usually care about) + value = self.get_cleansed_multivaluedict(request, value) + return value + + def get_traceback_frame_variables(self, request, tb_frame): + """ + Replaces the values of variables marked as sensitive with + stars (*********). + """ + # Loop through the frame's callers to see if the sensitive_variables + # decorator was used. + current_frame = tb_frame.f_back + sensitive_variables = None + while current_frame is not None: + if (current_frame.f_code.co_name == 'sensitive_variables_wrapper' + and 'sensitive_variables_wrapper' in current_frame.f_locals): + # The sensitive_variables decorator was used, so we take note + # of the sensitive variables' names. + wrapper = current_frame.f_locals['sensitive_variables_wrapper'] + sensitive_variables = getattr(wrapper, 'sensitive_variables', None) + break + current_frame = current_frame.f_back + + cleansed = {} + if self.is_active(request) and sensitive_variables: + if sensitive_variables == '__ALL__': + # Cleanse all variables + for name, value in tb_frame.f_locals.items(): + cleansed[name] = CLEANSED_SUBSTITUTE + else: + # Cleanse specified variables + for name, value in tb_frame.f_locals.items(): + if name in sensitive_variables: + value = CLEANSED_SUBSTITUTE + else: + value = self.cleanse_special_types(request, value) + cleansed[name] = value + else: + # Potentially cleanse the request and any MultiValueDicts if they + # are one of the frame variables. + for name, value in tb_frame.f_locals.items(): + cleansed[name] = self.cleanse_special_types(request, value) + + if (tb_frame.f_code.co_name == 'sensitive_variables_wrapper' + and 'sensitive_variables_wrapper' in tb_frame.f_locals): + # For good measure, obfuscate the decorated function's arguments in + # the sensitive_variables decorator's frame, in case the variables + # associated with those arguments were meant to be obfuscated from + # the decorated function's frame. + cleansed['func_args'] = CLEANSED_SUBSTITUTE + cleansed['func_kwargs'] = CLEANSED_SUBSTITUTE + + return cleansed.items() + +class ExceptionReporter(object): + """ + A class to organize and coordinate reporting on exceptions. + """ + def __init__(self, request, exc_type, exc_value, tb, is_email=False): + self.request = request + self.filter = get_exception_reporter_filter(self.request) + self.exc_type = exc_type + self.exc_value = exc_value + self.tb = tb + self.is_email = is_email + + self.template_info = None + self.template_does_not_exist = False + self.loader_debug_info = None + + # Handle deprecated string exceptions + if isinstance(self.exc_type, six.string_types): + self.exc_value = Exception('Deprecated String Exception: %r' % self.exc_type) + self.exc_type = type(self.exc_value) + + def format_path_status(self, path): + if not os.path.exists(path): + return "File does not exist" + if not os.path.isfile(path): + return "Not a file" + if not os.access(path, os.R_OK): + return "File is not readable" + return "File exists" + + def get_traceback_data(self): + "Return a Context instance containing traceback information." + + if self.exc_type and issubclass(self.exc_type, TemplateDoesNotExist): + from django.template.loader import template_source_loaders + self.template_does_not_exist = True + self.loader_debug_info = [] + # If the template_source_loaders haven't been populated yet, you need + # to provide an empty list for this for loop to not fail. + if template_source_loaders is None: + template_source_loaders = [] + for loader in template_source_loaders: + try: + source_list_func = loader.get_template_sources + # NOTE: This assumes exc_value is the name of the template that + # the loader attempted to load. + template_list = [{ + 'name': t, + 'status': self.format_path_status(t), + } for t in source_list_func(str(self.exc_value))] + except AttributeError: + template_list = [] + loader_name = loader.__module__ + '.' + loader.__class__.__name__ + self.loader_debug_info.append({ + 'loader': loader_name, + 'templates': template_list, + }) + if (settings.TEMPLATE_DEBUG and + hasattr(self.exc_value, 'django_template_source')): + self.get_template_exception_info() + + frames = self.get_traceback_frames() + for i, frame in enumerate(frames): + if 'vars' in frame: + frame['vars'] = [(k, force_escape(pprint(v))) for k, v in frame['vars']] + frames[i] = frame + + unicode_hint = '' + if self.exc_type and 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_text(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace') + from django import get_version + c = { + 'is_email': self.is_email, + 'unicode_hint': unicode_hint, + 'frames': frames, + 'request': self.request, + 'filtered_POST': self.filter.get_post_parameters(self.request), + '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, + } + # Check whether exception info is available + if self.exc_type: + c['exception_type'] = self.exc_type.__name__ + if self.exc_value: + c['exception_value'] = smart_text(self.exc_value, errors='replace') + if frames: + c['lastframe'] = frames[-1] + return c + + def get_traceback_html(self): + "Return HTML version of debug 500 HTTP error page." + t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') + c = Context(self.get_traceback_data()) + return t.render(c) + + def get_traceback_text(self): + "Return plain text version of debug 500 HTTP error page." + t = Template(TECHNICAL_500_TEXT_TEMPLATE, name='Technical 500 template') + c = Context(self.get_traceback_data(), autoescape=False) + return t.render(c) + + def get_template_exception_info(self): + origin, (start, end) = self.exc_value.django_template_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) + + # In some rare cases, exc_value.args might be empty. + try: + message = self.exc_value.args[0] + except IndexError: + message = '(Could not get exception message)' + + self.template_info = { + 'message': message, + '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"): + try: + source = loader.get_source(module_name) + except ImportError: + pass + if source is not None: + source = source.splitlines() + if source is None: + try: + with open(filename, 'rb') as fp: + source = fp.read().splitlines() + except (OSError, IOError): + pass + if source is None: + return None, [], None, [] + + # If we just read the source from a file, or if the loader did not + # apply tokenize.detect_encoding to decode the source into a Unicode + # string, then we should do that ourselves. + if isinstance(source[0], six.binary_type): + 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(br'coding[:=]\s*([-\w.]+)', line) + if match: + encoding = match.group(1).decode('ascii') + break + source = [six.text_type(sline, encoding, 'replace') for sline in source] + + lower_bound = max(0, lineno - context_lines) + upper_bound = lineno + context_lines + + pre_context = source[lower_bound:lineno] + context_line = source[lineno] + post_context = 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__') or '' + 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, + 'type': 'django' if module_name.startswith('django.') else 'user', + 'filename': filename, + 'function': function, + 'lineno': lineno + 1, + 'vars': self.filter.get_traceback_frame_variables(self.request, tb.tb_frame), + '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 + + 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 list + + +def 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, KeyError): + tried = [] + else: + if (not tried # empty URLconf + or (request.path == '/' + and len(tried) == 1 # default URLconf + and len(tried[0]) == 1 + and getattr(tried[0][0], 'app_name', '') == getattr(tried[0][0], 'namespace', '') == 'admin')): + return default_urlconf(request) + + urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) + if isinstance(urlconf, types.ModuleType): + urlconf = urlconf.__name__ + + t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') + c = Context({ + 'urlconf': urlconf, + 'root_urlconf': settings.ROOT_URLCONF, + 'request_path': request.path_info[1:], # Trim leading slash + 'urlpatterns': tried, + 'reason': force_bytes(exception, errors='replace'), + 'request': request, + 'settings': get_safe_settings(), + }) + return HttpResponseNotFound(t.render(c), content_type='text/html') + +def default_urlconf(request): + "Create an empty URLconf 404 error response." + t = Template(DEFAULT_URLCONF_TEMPLATE, name='Default URLconf template') + c = Context({}) + return HttpResponse(t.render(c), content_type='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> +<html lang="en"> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <meta name="robots" content="NONE,NOARCHIVE"> + <title>{% if exception_type %}{{ exception_type }}{% else %}Report{% endif %}{% if request %} at {{ request.path_info|escape }}{% endif %}</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; } + code, pre { font-size: 100%; white-space: pre-wrap; } + 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 pre { 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; color: #222; } + ul.traceback li.frame { padding-bottom:1em; color:#666; } + ul.traceback li.user { background-color:#e0e0e0; color:#000 } + div.context { padding:10px 0; overflow:hidden; } + div.context ol { padding-left:30px; margin:0 10px; list-style-position: inside; } + div.context ol li { font-family:monospace; white-space:pre; color:#777; cursor:pointer; } + div.context ol li pre { display:inline; } + div.context ol.context-line li { color:#505050; background-color:#dfdfdf; } + div.context ol.context-line li span { position:absolute; right:32px; } + .user div.context ol.context-line li { background-color:#bbb; color:#000; } + .user div.context ol li { color:#666; } + div.commands { margin-left: 40px; } + div.commands a { color:#555; text-decoration:none; } + .user div.commands a { color: black; } + #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> + {% if not is_email %} + <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> + {% endif %} +</head> +<body> +<div id="summary"> + <h1>{% if exception_type %}{{ exception_type }}{% else %}Report{% endif %}{% if request %} at {{ request.path_info|escape }}{% endif %}</h1> + <pre class="exception_value">{% if exception_value %}{{ exception_value|force_escape }}{% else %}No exception message supplied{% endif %}</pre> + <table class="meta"> +{% if request %} + <tr> + <th>Request Method:</th> + <td>{{ request.META.REQUEST_METHOD }}</td> + </tr> + <tr> + <th>Request URL:</th> + <td>{{ request.build_absolute_uri|escape }}</td> + </tr> +{% endif %} + <tr> + <th>Django Version:</th> + <td>{{ django_version_info }}</td> + </tr> +{% if exception_type %} + <tr> + <th>Exception Type:</th> + <td>{{ exception_type }}</td> + </tr> +{% endif %} +{% if exception_type and exception_value %} + <tr> + <th>Exception Value:</th> + <td><pre>{{ exception_value|force_escape }}</pre></td> + </tr> +{% endif %} +{% if lastframe %} + <tr> + <th>Exception Location:</th> + <td>{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}</td> + </tr> +{% endif %} + <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><pre>{{ sys_path|pprint }}</pre></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|force_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> ({{ t.status }})</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>Error during template rendering</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 %} +{% if frames %} +<div id="traceback"> + <h2>Traceback <span class="commands">{% if not is_email %}<a href="#" onclick="return switchPastebinFriendly(this);">Switch to copy-and-paste view</a></span>{% endif %}</h2> + {% autoescape off %} + <div id="browserTraceback"> + <ul class="traceback"> + {% for frame in frames %} + <li class="frame {{ frame.type }}"> + <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 and not is_email %} + <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 }}')"><pre>{{ line|escape }}</pre></li>{% endfor %}</ol> + {% endif %} + <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')"><pre>{{ frame.context_line|escape }}</pre>{% if not is_email %} <span>...</span>{% endif %}</li></ol> + {% if frame.post_context and not is_email %} + <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 }}')"><pre>{{ line|escape }}</pre></li>{% endfor %}</ol> + {% endif %} + </div> + {% endif %} + + {% if frame.vars %} + <div class="commands"> + {% if is_email %} + <h2>Local Vars</h2> + {% else %} + <a href="#" onclick="return varToggle(this, '{{ frame.id }}')"><span>▶</span> Local vars</a> + {% endif %} + </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|force_escape }}</td> + <td class="code"><pre>{{ var.1 }}</pre></td> + </tr> + {% endfor %} + </tbody> + </table> + {% endif %} + </li> + {% endfor %} + </ul> + </div> + {% endautoescape %} + <form action="http://dpaste.com/" name="pasteform" id="pasteform" method="post"> +{% if not is_email %} + <div id="pastebinTraceback" class="pastebin"> + <input type="hidden" name="language" value="PythonConsole"> + <input type="hidden" name="title" value="{{ exception_type|escape }}{% if request %} at {{ request.path_info|escape }}{% endif %}"> + <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: + +{% if request %} +Request Method: {{ request.META.REQUEST_METHOD }} +Request URL: {{ request.build_absolute_uri|escape }} +{% endif %} +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 }} ({{ t.status }}) +{% 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 }}{% if request %} at {{ request.path_info|escape }}{% endif %} +Exception Value: {{ exception_value|force_escape }} +</textarea> + <br><br> + <input type="submit" value="Share this traceback on a public Web site"> + </div> +</form> +</div> +{% endif %} +{% endif %} + +<div id="requestinfo"> + <h2>Request information</h2> + +{% if request %} + <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"><pre>{{ var.1|pprint }}</pre></td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <p>No GET data</p> + {% endif %} + + <h3 id="post-info">POST</h3> + {% if filtered_POST %} + <table class="req"> + <thead> + <tr> + <th>Variable</th> + <th>Value</th> + </tr> + </thead> + <tbody> + {% for var in filtered_POST.items %} + <tr> + <td>{{ var.0 }}</td> + <td class="code"><pre>{{ var.1|pprint }}</pre></td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <p>No POST data</p> + {% endif %} + <h3 id="files-info">FILES</h3> + {% if request.FILES %} + <table class="req"> + <thead> + <tr> + <th>Variable</th> + <th>Value</th> + </tr> + </thead> + <tbody> + {% for var in request.FILES.items %} + <tr> + <td>{{ var.0 }}</td> + <td class="code"><pre>{{ var.1|pprint }}</pre></td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <p>No FILES 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"><pre>{{ var.1|pprint }}</pre></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"><pre>{{ var.1|pprint }}</pre></td> + </tr> + {% endfor %} + </tbody> + </table> +{% else %} + <p>Request data not supplied</p> +{% endif %} + + <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"><pre>{{ var.1|pprint }}</pre></td> + </tr> + {% endfor %} + </tbody> + </table> + +</div> +{% if not is_email %} + <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> +{% endif %} +</body> +</html> +""" + +TECHNICAL_500_TEXT_TEMPLATE = """{% load firstof from future %}{% firstof exception_type 'Report' %}{% if request %} at {{ request.path_info }}{% endif %} +{% firstof exception_value 'No exception message supplied' %} +{% if request %} +Request Method: {{ request.META.REQUEST_METHOD }} +Request URL: {{ request.build_absolute_uri }}{% endif %} +Django Version: {{ django_version_info }} +Python Executable: {{ sys_executable }} +Python Version: {{ sys_version_info }} +Python Path: {{ sys_path }} +Server time: {{server_time|date:"r"}} +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 }} ({{ t.status }}) +{% 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 %}{% if frames %} +Traceback: +{% for frame in frames %}File "{{ frame.filename }}" in {{ frame.function }} +{% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line }}{% endif %} +{% endfor %} +{% if exception_type %}Exception Type: {{ exception_type }}{% if request %} at {{ request.path_info }}{% endif %} +{% if exception_value %}Exception Value: {{ exception_value }}{% endif %}{% endif %}{% endif %} +{% if request %}Request information: +GET:{% for k, v in request.GET.items %} +{{ k }} = {{ v|stringformat:"r" }}{% empty %} No GET data{% endfor %} + +POST:{% for k, v in filtered_POST.items %} +{{ k }} = {{ v|stringformat:"r" }}{% empty %} No POST data{% endfor %} + +FILES:{% for k, v in request.FILES.items %} +{{ k }} = {{ v|stringformat:"r" }}{% empty %} No FILES data{% endfor %} + +COOKIES:{% for k, v in request.COOKIES.items %} +{{ k }} = {{ v|stringformat:"r" }}{% empty %} No cookie data{% endfor %} + +META:{% for k, v in request.META.items|dictsort:"0" %} +{{ k }} = {{ v|stringformat:"r" }}{% endfor %} +{% else %}Request data not supplied +{% endif %} +Settings: +Using settings module {{ settings.SETTINGS_MODULE }}{% for k, v in settings.items|dictsort:"0" %} +{{ k }} = {{ v|stringformat:"r" }}{% endfor %} + +You're seeing this error because you have DEBUG = True in your +Django settings file. Change that to False, and Django will +display a standard 500 page. +""" + +TECHNICAL_404_TEMPLATE = """ +<!DOCTYPE html> +<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.build_absolute_uri|escape }}</td> + </tr> + </table> + </div> + <div id="info"> + {% if urlpatterns %} + <p> + Using the URLconf defined in <code>{{ urlconf }}</code>, + Django tried these URL patterns, in this order: + </p> + <ol> + {% for pattern in urlpatterns %} + <li> + {% for pat in pattern %} + {{ pat.regex.pattern }} + {% if forloop.last and pat.name %}[name='{{ pat.name }}']{% endif %} + {% endfor %} + </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> +""" + +DEFAULT_URLCONF_TEMPLATE = """ +<!DOCTYPE html> +<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; } + #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. + Next, start your first app by running <code>python manage.py startapp [appname]</code>. + </p> +</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> +""" diff --git a/lib/python2.7/site-packages/django/views/decorators/__init__.py b/lib/python2.7/site-packages/django/views/decorators/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/__init__.py diff --git a/lib/python2.7/site-packages/django/views/decorators/cache.py b/lib/python2.7/site-packages/django/views/decorators/cache.py new file mode 100644 index 0000000..001e21c --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/cache.py @@ -0,0 +1,55 @@ +from functools import wraps +from django.utils.decorators import decorator_from_middleware_with_args, available_attrs +from django.utils.cache import patch_cache_control, add_never_cache_headers +from django.middleware.cache import CacheMiddleware + + +def cache_page(*args, **kwargs): + """ + Decorator for views that tries getting the page from the cache and + populates the cache if the page isn't in the cache yet. + + The cache is keyed by the URL and some data from the headers. + Additionally there is the key prefix that is used to distinguish different + cache areas in a multi-site setup. You could use the + sites.get_current_site().domain, for example, as that is unique across a Django + project. + + Additionally, all headers from the response's Vary header will be taken + into account on caching -- just like the middleware does. + """ + # We also add some asserts to give better error messages in case people are + # using other ways to call cache_page that no longer work. + if len(args) != 1 or callable(args[0]): + raise TypeError("cache_page has a single mandatory positional argument: timeout") + cache_timeout = args[0] + cache_alias = kwargs.pop('cache', None) + key_prefix = kwargs.pop('key_prefix', None) + if kwargs: + raise TypeError("cache_page has two optional keyword arguments: cache and key_prefix") + + return decorator_from_middleware_with_args(CacheMiddleware)(cache_timeout=cache_timeout, cache_alias=cache_alias, key_prefix=key_prefix) + + +def cache_control(**kwargs): + def _cache_controller(viewfunc): + @wraps(viewfunc, assigned=available_attrs(viewfunc)) + def _cache_controlled(request, *args, **kw): + response = viewfunc(request, *args, **kw) + patch_cache_control(response, **kwargs) + return response + return _cache_controlled + return _cache_controller + + +def never_cache(view_func): + """ + Decorator that adds headers to a response so that it will + never be cached. + """ + @wraps(view_func, assigned=available_attrs(view_func)) + def _wrapped_view_func(request, *args, **kwargs): + response = view_func(request, *args, **kwargs) + add_never_cache_headers(response) + return response + return _wrapped_view_func diff --git a/lib/python2.7/site-packages/django/views/decorators/clickjacking.py b/lib/python2.7/site-packages/django/views/decorators/clickjacking.py new file mode 100644 index 0000000..fcd7887 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/clickjacking.py @@ -0,0 +1,64 @@ +from functools import wraps + +from django.utils.decorators import available_attrs + + +def xframe_options_deny(view_func): + """ + Modifies a view function so its response has the X-Frame-Options HTTP + header set to 'DENY' as long as the response doesn't already have that + header set. + + e.g. + + @xframe_options_deny + def some_view(request): + ... + + """ + def wrapped_view(*args, **kwargs): + resp = view_func(*args, **kwargs) + if resp.get('X-Frame-Options', None) is None: + resp['X-Frame-Options'] = 'DENY' + return resp + return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) + + +def xframe_options_sameorigin(view_func): + """ + Modifies a view function so its response has the X-Frame-Options HTTP + header set to 'SAMEORIGIN' as long as the response doesn't already have + that header set. + + e.g. + + @xframe_options_sameorigin + def some_view(request): + ... + + """ + def wrapped_view(*args, **kwargs): + resp = view_func(*args, **kwargs) + if resp.get('X-Frame-Options', None) is None: + resp['X-Frame-Options'] = 'SAMEORIGIN' + return resp + return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) + + +def xframe_options_exempt(view_func): + """ + Modifies a view function by setting a response variable that instructs + XFrameOptionsMiddleware to NOT set the X-Frame-Options HTTP header. + + e.g. + + @xframe_options_exempt + def some_view(request): + ... + + """ + def wrapped_view(*args, **kwargs): + resp = view_func(*args, **kwargs) + resp.xframe_options_exempt = True + return resp + return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) diff --git a/lib/python2.7/site-packages/django/views/decorators/csrf.py b/lib/python2.7/site-packages/django/views/decorators/csrf.py new file mode 100644 index 0000000..1ebed2a --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/csrf.py @@ -0,0 +1,59 @@ +from django.middleware.csrf import CsrfViewMiddleware, get_token +from django.utils.decorators import decorator_from_middleware, available_attrs +from functools import wraps + +csrf_protect = decorator_from_middleware(CsrfViewMiddleware) +csrf_protect.__name__ = "csrf_protect" +csrf_protect.__doc__ = """ +This decorator adds CSRF protection in exactly the same way as +CsrfViewMiddleware, but it can be used on a per view basis. Using both, or +using the decorator multiple times, is harmless and efficient. +""" + + +class _EnsureCsrfToken(CsrfViewMiddleware): + # We need this to behave just like the CsrfViewMiddleware, but not reject + # requests or log warnings. + def _reject(self, request, reason): + return None + + +requires_csrf_token = decorator_from_middleware(_EnsureCsrfToken) +requires_csrf_token.__name__ = 'requires_csrf_token' +requires_csrf_token.__doc__ = """ +Use this decorator on views that need a correct csrf_token available to +RequestContext, but without the CSRF protection that csrf_protect +enforces. +""" + + +class _EnsureCsrfCookie(CsrfViewMiddleware): + def _reject(self, request, reason): + return None + + def process_view(self, request, callback, callback_args, callback_kwargs): + retval = super(_EnsureCsrfCookie, self).process_view(request, callback, callback_args, callback_kwargs) + # Forces process_response to send the cookie + get_token(request) + return retval + + +ensure_csrf_cookie = decorator_from_middleware(_EnsureCsrfCookie) +ensure_csrf_cookie.__name__ = 'ensure_csrf_cookie' +ensure_csrf_cookie.__doc__ = """ +Use this decorator to ensure that a view sets a CSRF cookie, whether or not it +uses the csrf_token template tag, or the CsrfViewMiddleware is used. +""" + + +def csrf_exempt(view_func): + """ + Marks a view function as being exempt from the CSRF view protection. + """ + # We could just do view_func.csrf_exempt = True, but decorators + # are nicer if they don't have side-effects, so we return a new + # function. + def wrapped_view(*args, **kwargs): + return view_func(*args, **kwargs) + wrapped_view.csrf_exempt = True + return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) diff --git a/lib/python2.7/site-packages/django/views/decorators/debug.py b/lib/python2.7/site-packages/django/views/decorators/debug.py new file mode 100644 index 0000000..a611981 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/debug.py @@ -0,0 +1,77 @@ +import functools + +from django.http import HttpRequest + + +def sensitive_variables(*variables): + """ + Indicates which variables used in the decorated function are sensitive, so + that those variables can later be treated in a special way, for example + by hiding them when logging unhandled exceptions. + + Two forms are accepted: + + * with specified variable names: + + @sensitive_variables('user', 'password', 'credit_card') + def my_function(user): + password = user.pass_word + credit_card = user.credit_card_number + ... + + * without any specified variable names, in which case it is assumed that + all variables are considered sensitive: + + @sensitive_variables() + def my_function() + ... + """ + def decorator(func): + @functools.wraps(func) + def sensitive_variables_wrapper(*func_args, **func_kwargs): + if variables: + sensitive_variables_wrapper.sensitive_variables = variables + else: + sensitive_variables_wrapper.sensitive_variables = '__ALL__' + return func(*func_args, **func_kwargs) + return sensitive_variables_wrapper + return decorator + + +def sensitive_post_parameters(*parameters): + """ + Indicates which POST parameters used in the decorated view are sensitive, + so that those parameters can later be treated in a special way, for example + by hiding them when logging unhandled exceptions. + + Two forms are accepted: + + * with specified parameters: + + @sensitive_post_parameters('password', 'credit_card') + def my_view(request): + pw = request.POST['password'] + cc = request.POST['credit_card'] + ... + + * without any specified parameters, in which case it is assumed that + all parameters are considered sensitive: + + @sensitive_post_parameters() + def my_view(request) + ... + """ + def decorator(view): + @functools.wraps(view) + def sensitive_post_parameters_wrapper(request, *args, **kwargs): + assert isinstance(request, HttpRequest), ( + "sensitive_post_parameters didn't receive an HttpRequest. If you " + "are decorating a classmethod, be sure to use @method_decorator." + ) + if parameters: + request.sensitive_post_parameters = parameters + else: + request.sensitive_post_parameters = '__ALL__' + return view(request, *args, **kwargs) + return sensitive_post_parameters_wrapper + return decorator diff --git a/lib/python2.7/site-packages/django/views/decorators/gzip.py b/lib/python2.7/site-packages/django/views/decorators/gzip.py new file mode 100644 index 0000000..f5b009d --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/gzip.py @@ -0,0 +1,5 @@ +from django.utils.decorators import decorator_from_middleware +from django.middleware.gzip import GZipMiddleware + +gzip_page = decorator_from_middleware(GZipMiddleware) +gzip_page.__doc__ = "Decorator for views that gzips pages if the client supports it." diff --git a/lib/python2.7/site-packages/django/views/decorators/http.py b/lib/python2.7/site-packages/django/views/decorators/http.py new file mode 100644 index 0000000..410979e --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/http.py @@ -0,0 +1,166 @@ +""" +Decorators for views based on HTTP headers. +""" + +import logging +from calendar import timegm +from functools import wraps + +from django.utils.decorators import decorator_from_middleware, available_attrs +from django.utils.http import http_date, parse_http_date_safe, parse_etags, quote_etag +from django.middleware.http import ConditionalGetMiddleware +from django.http import HttpResponseNotAllowed, HttpResponseNotModified, HttpResponse + +conditional_page = decorator_from_middleware(ConditionalGetMiddleware) + +logger = logging.getLogger('django.request') + + +def require_http_methods(request_method_list): + """ + Decorator to make a view only accept particular request methods. Usage:: + + @require_http_methods(["GET", "POST"]) + def my_view(request): + # I can assume now that only GET or POST requests make it this far + # ... + + Note that request methods should be in uppercase. + """ + def decorator(func): + @wraps(func, assigned=available_attrs(func)) + def inner(request, *args, **kwargs): + if request.method not in request_method_list: + logger.warning('Method Not Allowed (%s): %s', request.method, request.path, + extra={ + 'status_code': 405, + 'request': request + } + ) + return HttpResponseNotAllowed(request_method_list) + return func(request, *args, **kwargs) + return inner + return decorator + +require_GET = require_http_methods(["GET"]) +require_GET.__doc__ = "Decorator to require that a view only accept the GET method." + +require_POST = require_http_methods(["POST"]) +require_POST.__doc__ = "Decorator to require that a view only accept the POST method." + +require_safe = require_http_methods(["GET", "HEAD"]) +require_safe.__doc__ = "Decorator to require that a view only accept safe methods: GET and HEAD." + +def condition(etag_func=None, last_modified_func=None): + """ + Decorator to support conditional retrieval (or change) for a view + function. + + The parameters are callables to compute the ETag and last modified time for + the requested resource, respectively. The callables are passed the same + parameters as the view itself. The Etag function should return a string (or + None if the resource doesn't exist), whilst the last_modified function + should return a datetime object (or None if the resource doesn't exist). + + If both parameters are provided, all the preconditions must be met before + the view is processed. + + This decorator will either pass control to the wrapped view function or + return an HTTP 304 response (unmodified) or 412 response (preconditions + failed), depending upon the request method. + + Any behavior marked as "undefined" in the HTTP spec (e.g. If-none-match + plus If-modified-since headers) will result in the view function being + called. + """ + def decorator(func): + @wraps(func, assigned=available_attrs(func)) + def inner(request, *args, **kwargs): + # Get HTTP request headers + if_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE") + if if_modified_since: + if_modified_since = parse_http_date_safe(if_modified_since) + if_none_match = request.META.get("HTTP_IF_NONE_MATCH") + if_match = request.META.get("HTTP_IF_MATCH") + if if_none_match or if_match: + # There can be more than one ETag in the request, so we + # consider the list of values. + try: + etags = parse_etags(if_none_match or if_match) + except ValueError: + # In case of invalid etag ignore all ETag headers. + # Apparently Opera sends invalidly quoted headers at times + # (we should be returning a 400 response, but that's a + # little extreme) -- this is Django bug #10681. + if_none_match = None + if_match = None + + # Compute values (if any) for the requested resource. + if etag_func: + res_etag = etag_func(request, *args, **kwargs) + else: + res_etag = None + if last_modified_func: + dt = last_modified_func(request, *args, **kwargs) + if dt: + res_last_modified = timegm(dt.utctimetuple()) + else: + res_last_modified = None + else: + res_last_modified = None + + response = None + if not ((if_match and (if_modified_since or if_none_match)) or + (if_match and if_none_match)): + # We only get here if no undefined combinations of headers are + # specified. + if ((if_none_match and (res_etag in etags or + "*" in etags and res_etag)) and + (not if_modified_since or + (res_last_modified and if_modified_since and + res_last_modified <= if_modified_since))): + if request.method in ("GET", "HEAD"): + response = HttpResponseNotModified() + else: + logger.warning('Precondition Failed: %s', request.path, + extra={ + 'status_code': 412, + 'request': request + } + ) + response = HttpResponse(status=412) + elif if_match and ((not res_etag and "*" in etags) or + (res_etag and res_etag not in etags)): + logger.warning('Precondition Failed: %s', request.path, + extra={ + 'status_code': 412, + 'request': request + } + ) + response = HttpResponse(status=412) + elif (not if_none_match and request.method == "GET" and + res_last_modified and if_modified_since and + res_last_modified <= if_modified_since): + response = HttpResponseNotModified() + + if response is None: + response = func(request, *args, **kwargs) + + # Set relevant headers on the response if they don't already exist. + if res_last_modified and not response.has_header('Last-Modified'): + response['Last-Modified'] = http_date(res_last_modified) + if res_etag and not response.has_header('ETag'): + response['ETag'] = quote_etag(res_etag) + + return response + + return inner + return decorator + +# Shortcut decorators for common cases based on ETag or Last-Modified only +def etag(etag_func): + return condition(etag_func=etag_func) + +def last_modified(last_modified_func): + return condition(last_modified_func=last_modified_func) + diff --git a/lib/python2.7/site-packages/django/views/decorators/vary.py b/lib/python2.7/site-packages/django/views/decorators/vary.py new file mode 100644 index 0000000..cd2f9c0 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/decorators/vary.py @@ -0,0 +1,39 @@ +from functools import wraps +from django.utils.cache import patch_vary_headers +from django.utils.decorators import available_attrs + +def vary_on_headers(*headers): + """ + A view decorator that adds the specified headers to the Vary header of the + response. Usage: + + @vary_on_headers('Cookie', 'Accept-language') + def index(request): + ... + + Note that the header names are not case-sensitive. + """ + def decorator(func): + @wraps(func, assigned=available_attrs(func)) + def inner_func(*args, **kwargs): + response = func(*args, **kwargs) + patch_vary_headers(response, headers) + return response + return inner_func + return decorator + +def vary_on_cookie(func): + """ + A view decorator that adds "Cookie" to the Vary header of a response. This + indicates that a page's contents depends on cookies. Usage: + + @vary_on_cookie + def index(request): + ... + """ + @wraps(func, assigned=available_attrs(func)) + def inner_func(*args, **kwargs): + response = func(*args, **kwargs) + patch_vary_headers(response, ('Cookie',)) + return response + return inner_func diff --git a/lib/python2.7/site-packages/django/views/defaults.py b/lib/python2.7/site-packages/django/views/defaults.py new file mode 100644 index 0000000..d531f22 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/defaults.py @@ -0,0 +1,91 @@ +import warnings + +from django import http +from django.template import (Context, RequestContext, + loader, Template, TemplateDoesNotExist) +from django.views.decorators.csrf import requires_csrf_token + + +# This can be called when CsrfViewMiddleware.process_view has not run, +# therefore need @requires_csrf_token in case the template needs +# {% csrf_token %}. +@requires_csrf_token +def page_not_found(request, template_name='404.html'): + """ + Default 404 handler. + + Templates: :template:`404.html` + Context: + request_path + The path of the requested URL (e.g., '/app/pages/bad_page/') + """ + try: + template = loader.get_template(template_name) + content_type = None # Django will use DEFAULT_CONTENT_TYPE + except TemplateDoesNotExist: + template = Template( + '<h1>Not Found</h1>' + '<p>The requested URL {{ request_path }} was not found on this server.</p>') + content_type = 'text/html' + body = template.render(RequestContext(request, {'request_path': request.path})) + return http.HttpResponseNotFound(body, content_type=content_type) + + +@requires_csrf_token +def server_error(request, template_name='500.html'): + """ + 500 error handler. + + Templates: :template:`500.html` + Context: None + """ + try: + template = loader.get_template(template_name) + except TemplateDoesNotExist: + return http.HttpResponseServerError('<h1>Server Error (500)</h1>', content_type='text/html') + return http.HttpResponseServerError(template.render(Context({}))) + + +@requires_csrf_token +def bad_request(request, template_name='400.html'): + """ + 400 error handler. + + Templates: :template:`400.html` + Context: None + """ + try: + template = loader.get_template(template_name) + except TemplateDoesNotExist: + return http.HttpResponseBadRequest('<h1>Bad Request (400)</h1>', content_type='text/html') + return http.HttpResponseBadRequest(template.render(Context({}))) + + +# This can be called when CsrfViewMiddleware.process_view has not run, +# therefore need @requires_csrf_token in case the template needs +# {% csrf_token %}. +@requires_csrf_token +def permission_denied(request, template_name='403.html'): + """ + Permission denied (403) handler. + + Templates: :template:`403.html` + Context: None + + If the template does not exist, an Http403 response containing the text + "403 Forbidden" (as per RFC 2616) will be returned. + """ + try: + template = loader.get_template(template_name) + except TemplateDoesNotExist: + return http.HttpResponseForbidden('<h1>403 Forbidden</h1>', content_type='text/html') + return http.HttpResponseForbidden(template.render(RequestContext(request))) + + +def shortcut(request, content_type_id, object_id): + warnings.warn( + "django.views.defaults.shortcut will be removed in Django 1.8. " + "Import it from django.contrib.contenttypes.views instead.", + PendingDeprecationWarning, stacklevel=2) + from django.contrib.contenttypes.views import shortcut as real_shortcut + return real_shortcut(request, content_type_id, object_id) diff --git a/lib/python2.7/site-packages/django/views/generic/__init__.py b/lib/python2.7/site-packages/django/views/generic/__init__.py new file mode 100644 index 0000000..1a98067 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/generic/__init__.py @@ -0,0 +1,12 @@ +from django.views.generic.base import View, TemplateView, RedirectView +from django.views.generic.dates import (ArchiveIndexView, YearArchiveView, MonthArchiveView, + WeekArchiveView, DayArchiveView, TodayArchiveView, + DateDetailView) +from django.views.generic.detail import DetailView +from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView +from django.views.generic.list import ListView + + +class GenericViewError(Exception): + """A problem in a generic view.""" + pass diff --git a/lib/python2.7/site-packages/django/views/generic/base.py b/lib/python2.7/site-packages/django/views/generic/base.py new file mode 100644 index 0000000..2487ccb --- /dev/null +++ b/lib/python2.7/site-packages/django/views/generic/base.py @@ -0,0 +1,219 @@ +from __future__ import unicode_literals + +import logging +from functools import update_wrapper + +from django import http +from django.core.exceptions import ImproperlyConfigured +from django.core.urlresolvers import reverse, NoReverseMatch +from django.template.response import TemplateResponse +from django.utils.decorators import classonlymethod +from django.utils import six + +logger = logging.getLogger('django.request') + + +class ContextMixin(object): + """ + A default context mixin that passes the keyword arguments received by + get_context_data as the template context. + """ + + def get_context_data(self, **kwargs): + if 'view' not in kwargs: + kwargs['view'] = self + return kwargs + + +class View(object): + """ + Intentionally simple parent class for all views. Only implements + dispatch-by-method and simple sanity checking. + """ + + http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] + + def __init__(self, **kwargs): + """ + Constructor. Called in the URLconf; can contain helpful extra + keyword arguments, and other things. + """ + # Go through keyword arguments, and either save their values to our + # instance, or raise an error. + for key, value in six.iteritems(kwargs): + setattr(self, key, value) + + @classonlymethod + def as_view(cls, **initkwargs): + """ + Main entry point for a request-response process. + """ + # sanitize keyword arguments + for key in initkwargs: + if key in cls.http_method_names: + raise TypeError("You tried to pass in the %s method name as a " + "keyword argument to %s(). Don't do that." + % (key, cls.__name__)) + if not hasattr(cls, key): + raise TypeError("%s() received an invalid keyword %r. as_view " + "only accepts arguments that are already " + "attributes of the class." % (cls.__name__, key)) + + def view(request, *args, **kwargs): + self = cls(**initkwargs) + if hasattr(self, 'get') and not hasattr(self, 'head'): + self.head = self.get + self.request = request + self.args = args + self.kwargs = kwargs + return self.dispatch(request, *args, **kwargs) + + # take name and docstring from class + update_wrapper(view, cls, updated=()) + + # and possible attributes set by decorators + # like csrf_exempt from dispatch + update_wrapper(view, cls.dispatch, assigned=()) + return view + + def dispatch(self, request, *args, **kwargs): + # Try to dispatch to the right method; if a method doesn't exist, + # defer to the error handler. Also defer to the error handler if the + # request method isn't on the approved list. + if request.method.lower() in self.http_method_names: + handler = getattr(self, request.method.lower(), self.http_method_not_allowed) + else: + handler = self.http_method_not_allowed + return handler(request, *args, **kwargs) + + def http_method_not_allowed(self, request, *args, **kwargs): + logger.warning('Method Not Allowed (%s): %s', request.method, request.path, + extra={ + 'status_code': 405, + 'request': self.request + } + ) + return http.HttpResponseNotAllowed(self._allowed_methods()) + + def options(self, request, *args, **kwargs): + """ + Handles responding to requests for the OPTIONS HTTP verb. + """ + response = http.HttpResponse() + response['Allow'] = ', '.join(self._allowed_methods()) + response['Content-Length'] = '0' + return response + + def _allowed_methods(self): + return [m.upper() for m in self.http_method_names if hasattr(self, m)] + + +class TemplateResponseMixin(object): + """ + A mixin that can be used to render a template. + """ + template_name = None + response_class = TemplateResponse + content_type = None + + def render_to_response(self, context, **response_kwargs): + """ + Returns a response, using the `response_class` for this + view, with a template rendered with the given context. + + If any keyword arguments are provided, they will be + passed to the constructor of the response class. + """ + response_kwargs.setdefault('content_type', self.content_type) + return self.response_class( + request = self.request, + template = self.get_template_names(), + context = context, + **response_kwargs + ) + + def get_template_names(self): + """ + Returns a list of template names to be used for the request. Must return + a list. May not be called if render_to_response is overridden. + """ + if self.template_name is None: + raise ImproperlyConfigured( + "TemplateResponseMixin requires either a definition of " + "'template_name' or an implementation of 'get_template_names()'") + else: + return [self.template_name] + + +class TemplateView(TemplateResponseMixin, ContextMixin, View): + """ + A view that renders a template. This view will also pass into the context + any keyword arguments passed by the url conf. + """ + def get(self, request, *args, **kwargs): + context = self.get_context_data(**kwargs) + return self.render_to_response(context) + + +class RedirectView(View): + """ + A view that provides a redirect on any GET request. + """ + permanent = True + url = None + pattern_name = None + query_string = False + + def get_redirect_url(self, *args, **kwargs): + """ + Return the URL redirect to. Keyword arguments from the + URL pattern match generating the redirect request + are provided as kwargs to this method. + """ + if self.url: + url = self.url % kwargs + elif self.pattern_name: + try: + url = reverse(self.pattern_name, args=args, kwargs=kwargs) + except NoReverseMatch: + return None + else: + return None + + args = self.request.META.get('QUERY_STRING', '') + if args and self.query_string: + url = "%s?%s" % (url, args) + return url + + def get(self, request, *args, **kwargs): + url = self.get_redirect_url(*args, **kwargs) + if url: + if self.permanent: + return http.HttpResponsePermanentRedirect(url) + else: + return http.HttpResponseRedirect(url) + else: + logger.warning('Gone: %s', self.request.path, + extra={ + 'status_code': 410, + 'request': self.request + }) + return http.HttpResponseGone() + + def head(self, request, *args, **kwargs): + return self.get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + return self.get(request, *args, **kwargs) + + def options(self, request, *args, **kwargs): + return self.get(request, *args, **kwargs) + + def delete(self, request, *args, **kwargs): + return self.get(request, *args, **kwargs) + + def put(self, request, *args, **kwargs): + return self.get(request, *args, **kwargs) + + def patch(self, request, *args, **kwargs): + return self.get(request, *args, **kwargs) diff --git a/lib/python2.7/site-packages/django/views/generic/dates.py b/lib/python2.7/site-packages/django/views/generic/dates.py new file mode 100644 index 0000000..1b8ad3e --- /dev/null +++ b/lib/python2.7/site-packages/django/views/generic/dates.py @@ -0,0 +1,785 @@ +from __future__ import unicode_literals + +import datetime +from django.conf import settings +from django.db import models +from django.core.exceptions import ImproperlyConfigured +from django.http import Http404 +from django.utils.encoding import force_str, force_text +from django.utils.functional import cached_property +from django.utils.translation import ugettext as _ +from django.utils import timezone +from django.views.generic.base import View +from django.views.generic.detail import BaseDetailView, SingleObjectTemplateResponseMixin +from django.views.generic.list import MultipleObjectMixin, MultipleObjectTemplateResponseMixin + +class YearMixin(object): + """ + Mixin for views manipulating year-based data. + """ + year_format = '%Y' + year = None + + def get_year_format(self): + """ + Get a year format string in strptime syntax to be used to parse the + year from url variables. + """ + return self.year_format + + def get_year(self): + """ + Return the year for which this view should display data. + """ + year = self.year + if year is None: + try: + year = self.kwargs['year'] + except KeyError: + try: + year = self.request.GET['year'] + except KeyError: + raise Http404(_("No year specified")) + return year + + def get_next_year(self, date): + """ + Get the next valid year. + """ + return _get_next_prev(self, date, is_previous=False, period='year') + + def get_previous_year(self, date): + """ + Get the previous valid year. + """ + return _get_next_prev(self, date, is_previous=True, period='year') + + def _get_next_year(self, date): + """ + Return the start date of the next interval. + + The interval is defined by start date <= item date < next start date. + """ + return date.replace(year=date.year + 1, month=1, day=1) + + def _get_current_year(self, date): + """ + Return the start date of the current interval. + """ + return date.replace(month=1, day=1) + + +class MonthMixin(object): + """ + Mixin for views manipulating month-based data. + """ + month_format = '%b' + month = None + + def get_month_format(self): + """ + Get a month format string in strptime syntax to be used to parse the + month from url variables. + """ + return self.month_format + + def get_month(self): + """ + Return the month for which this view should display data. + """ + month = self.month + if month is None: + try: + month = self.kwargs['month'] + except KeyError: + try: + month = self.request.GET['month'] + except KeyError: + raise Http404(_("No month specified")) + return month + + def get_next_month(self, date): + """ + Get the next valid month. + """ + return _get_next_prev(self, date, is_previous=False, period='month') + + def get_previous_month(self, date): + """ + Get the previous valid month. + """ + return _get_next_prev(self, date, is_previous=True, period='month') + + def _get_next_month(self, date): + """ + Return the start date of the next interval. + + The interval is defined by start date <= item date < next start date. + """ + if date.month == 12: + return date.replace(year=date.year + 1, month=1, day=1) + else: + return date.replace(month=date.month + 1, day=1) + + def _get_current_month(self, date): + """ + Return the start date of the previous interval. + """ + return date.replace(day=1) + + +class DayMixin(object): + """ + Mixin for views manipulating day-based data. + """ + day_format = '%d' + day = None + + def get_day_format(self): + """ + Get a day format string in strptime syntax to be used to parse the day + from url variables. + """ + return self.day_format + + def get_day(self): + """ + Return the day for which this view should display data. + """ + day = self.day + if day is None: + try: + day = self.kwargs['day'] + except KeyError: + try: + day = self.request.GET['day'] + except KeyError: + raise Http404(_("No day specified")) + return day + + def get_next_day(self, date): + """ + Get the next valid day. + """ + return _get_next_prev(self, date, is_previous=False, period='day') + + def get_previous_day(self, date): + """ + Get the previous valid day. + """ + return _get_next_prev(self, date, is_previous=True, period='day') + + def _get_next_day(self, date): + """ + Return the start date of the next interval. + + The interval is defined by start date <= item date < next start date. + """ + return date + datetime.timedelta(days=1) + + def _get_current_day(self, date): + """ + Return the start date of the current interval. + """ + return date + + +class WeekMixin(object): + """ + Mixin for views manipulating week-based data. + """ + week_format = '%U' + week = None + + def get_week_format(self): + """ + Get a week format string in strptime syntax to be used to parse the + week from url variables. + """ + return self.week_format + + def get_week(self): + """ + Return the week for which this view should display data + """ + week = self.week + if week is None: + try: + week = self.kwargs['week'] + except KeyError: + try: + week = self.request.GET['week'] + except KeyError: + raise Http404(_("No week specified")) + return week + + def get_next_week(self, date): + """ + Get the next valid week. + """ + return _get_next_prev(self, date, is_previous=False, period='week') + + def get_previous_week(self, date): + """ + Get the previous valid week. + """ + return _get_next_prev(self, date, is_previous=True, period='week') + + def _get_next_week(self, date): + """ + Return the start date of the next interval. + + The interval is defined by start date <= item date < next start date. + """ + return date + datetime.timedelta(days=7 - self._get_weekday(date)) + + def _get_current_week(self, date): + """ + Return the start date of the current interval. + """ + return date - datetime.timedelta(self._get_weekday(date)) + + def _get_weekday(self, date): + """ + Return the weekday for a given date. + + The first day according to the week format is 0 and the last day is 6. + """ + week_format = self.get_week_format() + if week_format == '%W': # week starts on Monday + return date.weekday() + elif week_format == '%U': # week starts on Sunday + return (date.weekday() + 1) % 7 + else: + raise ValueError("unknown week format: %s" % week_format) + + +class DateMixin(object): + """ + Mixin class for views manipulating date-based data. + """ + date_field = None + allow_future = False + + def get_date_field(self): + """ + Get the name of the date field to be used to filter by. + """ + if self.date_field is None: + raise ImproperlyConfigured("%s.date_field is required." % self.__class__.__name__) + return self.date_field + + def get_allow_future(self): + """ + Returns `True` if the view should be allowed to display objects from + the future. + """ + return self.allow_future + + # Note: the following three methods only work in subclasses that also + # inherit SingleObjectMixin or MultipleObjectMixin. + + @cached_property + def uses_datetime_field(self): + """ + Return `True` if the date field is a `DateTimeField` and `False` + if it's a `DateField`. + """ + model = self.get_queryset().model if self.model is None else self.model + field = model._meta.get_field(self.get_date_field()) + return isinstance(field, models.DateTimeField) + + def _make_date_lookup_arg(self, value): + """ + Convert a date into a datetime when the date field is a DateTimeField. + + When time zone support is enabled, `date` is assumed to be in the + current time zone, so that displayed items are consistent with the URL. + """ + if self.uses_datetime_field: + value = datetime.datetime.combine(value, datetime.time.min) + if settings.USE_TZ: + value = timezone.make_aware(value, timezone.get_current_timezone()) + return value + + def _make_single_date_lookup(self, date): + """ + Get the lookup kwargs for filtering on a single date. + + If the date field is a DateTimeField, we can't just filter on + date_field=date because that doesn't take the time into account. + """ + date_field = self.get_date_field() + if self.uses_datetime_field: + since = self._make_date_lookup_arg(date) + until = self._make_date_lookup_arg(date + datetime.timedelta(days=1)) + return { + '%s__gte' % date_field: since, + '%s__lt' % date_field: until, + } + else: + # Skip self._make_date_lookup_arg, it's a no-op in this branch. + return {date_field: date} + + +class BaseDateListView(MultipleObjectMixin, DateMixin, View): + """ + Abstract base class for date-based views displaying a list of objects. + """ + allow_empty = False + date_list_period = 'year' + + def get(self, request, *args, **kwargs): + self.date_list, self.object_list, extra_context = self.get_dated_items() + context = self.get_context_data(object_list=self.object_list, + date_list=self.date_list) + context.update(extra_context) + return self.render_to_response(context) + + def get_dated_items(self): + """ + Obtain the list of dates and items. + """ + raise NotImplementedError('A DateView must provide an implementation of get_dated_items()') + + def get_dated_queryset(self, ordering=None, **lookup): + """ + Get a queryset properly filtered according to `allow_future` and any + extra lookup kwargs. + """ + qs = self.get_queryset().filter(**lookup) + date_field = self.get_date_field() + allow_future = self.get_allow_future() + allow_empty = self.get_allow_empty() + paginate_by = self.get_paginate_by(qs) + + if ordering is not None: + qs = qs.order_by(ordering) + + if not allow_future: + now = timezone.now() if self.uses_datetime_field else timezone_today() + qs = qs.filter(**{'%s__lte' % date_field: now}) + + if not allow_empty: + # When pagination is enabled, it's better to do a cheap query + # than to load the unpaginated queryset in memory. + is_empty = len(qs) == 0 if paginate_by is None else not qs.exists() + if is_empty: + raise Http404(_("No %(verbose_name_plural)s available") % { + 'verbose_name_plural': force_text(qs.model._meta.verbose_name_plural) + }) + + return qs + + def get_date_list_period(self): + """ + Get the aggregation period for the list of dates: 'year', 'month', or 'day'. + """ + return self.date_list_period + + def get_date_list(self, queryset, date_type=None, ordering='ASC'): + """ + Get a date list by calling `queryset.dates/datetimes()`, checking + along the way for empty lists that aren't allowed. + """ + date_field = self.get_date_field() + allow_empty = self.get_allow_empty() + if date_type is None: + date_type = self.get_date_list_period() + + if self.uses_datetime_field: + date_list = queryset.datetimes(date_field, date_type, ordering) + else: + date_list = queryset.dates(date_field, date_type, ordering) + if date_list is not None and not date_list and not allow_empty: + name = force_text(queryset.model._meta.verbose_name_plural) + raise Http404(_("No %(verbose_name_plural)s available") % + {'verbose_name_plural': name}) + + return date_list + + +class BaseArchiveIndexView(BaseDateListView): + """ + Base class for archives of date-based items. + + Requires a response mixin. + """ + context_object_name = 'latest' + + def get_dated_items(self): + """ + Return (date_list, items, extra_context) for this request. + """ + qs = self.get_dated_queryset(ordering='-%s' % self.get_date_field()) + date_list = self.get_date_list(qs, ordering='DESC') + + if not date_list: + qs = qs.none() + + return (date_list, qs, {}) + + +class ArchiveIndexView(MultipleObjectTemplateResponseMixin, BaseArchiveIndexView): + """ + Top-level archive of date-based items. + """ + template_name_suffix = '_archive' + + +class BaseYearArchiveView(YearMixin, BaseDateListView): + """ + List of objects published in a given year. + """ + date_list_period = 'month' + make_object_list = False + + def get_dated_items(self): + """ + Return (date_list, items, extra_context) for this request. + """ + year = self.get_year() + + date_field = self.get_date_field() + date = _date_from_string(year, self.get_year_format()) + + since = self._make_date_lookup_arg(date) + until = self._make_date_lookup_arg(self._get_next_year(date)) + lookup_kwargs = { + '%s__gte' % date_field: since, + '%s__lt' % date_field: until, + } + + qs = self.get_dated_queryset(ordering='-%s' % date_field, **lookup_kwargs) + date_list = self.get_date_list(qs) + + if not self.get_make_object_list(): + # We need this to be a queryset since parent classes introspect it + # to find information about the model. + qs = qs.none() + + return (date_list, qs, { + 'year': date, + 'next_year': self.get_next_year(date), + 'previous_year': self.get_previous_year(date), + }) + + def get_make_object_list(self): + """ + Return `True` if this view should contain the full list of objects in + the given year. + """ + return self.make_object_list + + +class YearArchiveView(MultipleObjectTemplateResponseMixin, BaseYearArchiveView): + """ + List of objects published in a given year. + """ + template_name_suffix = '_archive_year' + + +class BaseMonthArchiveView(YearMixin, MonthMixin, BaseDateListView): + """ + List of objects published in a given month. + """ + date_list_period = 'day' + + def get_dated_items(self): + """ + Return (date_list, items, extra_context) for this request. + """ + year = self.get_year() + month = self.get_month() + + date_field = self.get_date_field() + date = _date_from_string(year, self.get_year_format(), + month, self.get_month_format()) + + since = self._make_date_lookup_arg(date) + until = self._make_date_lookup_arg(self._get_next_month(date)) + lookup_kwargs = { + '%s__gte' % date_field: since, + '%s__lt' % date_field: until, + } + + qs = self.get_dated_queryset(**lookup_kwargs) + date_list = self.get_date_list(qs) + + return (date_list, qs, { + 'month': date, + 'next_month': self.get_next_month(date), + 'previous_month': self.get_previous_month(date), + }) + + +class MonthArchiveView(MultipleObjectTemplateResponseMixin, BaseMonthArchiveView): + """ + List of objects published in a given month. + """ + template_name_suffix = '_archive_month' + + +class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView): + """ + List of objects published in a given week. + """ + + def get_dated_items(self): + """ + Return (date_list, items, extra_context) for this request. + """ + year = self.get_year() + week = self.get_week() + + date_field = self.get_date_field() + week_format = self.get_week_format() + week_start = { + '%W': '1', + '%U': '0', + }[week_format] + date = _date_from_string(year, self.get_year_format(), + week_start, '%w', + week, week_format) + + since = self._make_date_lookup_arg(date) + until = self._make_date_lookup_arg(self._get_next_week(date)) + lookup_kwargs = { + '%s__gte' % date_field: since, + '%s__lt' % date_field: until, + } + + qs = self.get_dated_queryset(**lookup_kwargs) + + return (None, qs, { + 'week': date, + 'next_week': self.get_next_week(date), + 'previous_week': self.get_previous_week(date), + }) + + +class WeekArchiveView(MultipleObjectTemplateResponseMixin, BaseWeekArchiveView): + """ + List of objects published in a given week. + """ + template_name_suffix = '_archive_week' + + +class BaseDayArchiveView(YearMixin, MonthMixin, DayMixin, BaseDateListView): + """ + List of objects published on a given day. + """ + def get_dated_items(self): + """ + Return (date_list, items, extra_context) for this request. + """ + year = self.get_year() + month = self.get_month() + day = self.get_day() + + date = _date_from_string(year, self.get_year_format(), + month, self.get_month_format(), + day, self.get_day_format()) + + return self._get_dated_items(date) + + def _get_dated_items(self, date): + """ + Do the actual heavy lifting of getting the dated items; this accepts a + date object so that TodayArchiveView can be trivial. + """ + lookup_kwargs = self._make_single_date_lookup(date) + qs = self.get_dated_queryset(**lookup_kwargs) + + return (None, qs, { + 'day': date, + 'previous_day': self.get_previous_day(date), + 'next_day': self.get_next_day(date), + 'previous_month': self.get_previous_month(date), + 'next_month': self.get_next_month(date) + }) + + +class DayArchiveView(MultipleObjectTemplateResponseMixin, BaseDayArchiveView): + """ + List of objects published on a given day. + """ + template_name_suffix = "_archive_day" + + +class BaseTodayArchiveView(BaseDayArchiveView): + """ + List of objects published today. + """ + + def get_dated_items(self): + """ + Return (date_list, items, extra_context) for this request. + """ + return self._get_dated_items(datetime.date.today()) + + +class TodayArchiveView(MultipleObjectTemplateResponseMixin, BaseTodayArchiveView): + """ + List of objects published today. + """ + template_name_suffix = "_archive_day" + + +class BaseDateDetailView(YearMixin, MonthMixin, DayMixin, DateMixin, BaseDetailView): + """ + Detail view of a single object on a single date; this differs from the + standard DetailView by accepting a year/month/day in the URL. + """ + def get_object(self, queryset=None): + """ + Get the object this request displays. + """ + year = self.get_year() + month = self.get_month() + day = self.get_day() + date = _date_from_string(year, self.get_year_format(), + month, self.get_month_format(), + day, self.get_day_format()) + + # Use a custom queryset if provided + qs = queryset or self.get_queryset() + + if not self.get_allow_future() and date > datetime.date.today(): + raise Http404(_("Future %(verbose_name_plural)s not available because %(class_name)s.allow_future is False.") % { + 'verbose_name_plural': qs.model._meta.verbose_name_plural, + 'class_name': self.__class__.__name__, + }) + + # Filter down a queryset from self.queryset using the date from the + # URL. This'll get passed as the queryset to DetailView.get_object, + # which'll handle the 404 + lookup_kwargs = self._make_single_date_lookup(date) + qs = qs.filter(**lookup_kwargs) + + return super(BaseDetailView, self).get_object(queryset=qs) + + +class DateDetailView(SingleObjectTemplateResponseMixin, BaseDateDetailView): + """ + Detail view of a single object on a single date; this differs from the + standard DetailView by accepting a year/month/day in the URL. + """ + template_name_suffix = '_detail' + + +def _date_from_string(year, year_format, month='', month_format='', day='', day_format='', delim='__'): + """ + Helper: get a datetime.date object given a format string and a year, + month, and day (only year is mandatory). Raise a 404 for an invalid date. + """ + format = delim.join((year_format, month_format, day_format)) + datestr = delim.join((year, month, day)) + try: + return datetime.datetime.strptime(force_str(datestr), format).date() + except ValueError: + raise Http404(_("Invalid date string '%(datestr)s' given format '%(format)s'") % { + 'datestr': datestr, + 'format': format, + }) + + +def _get_next_prev(generic_view, date, is_previous, period): + """ + Helper: Get the next or the previous valid date. The idea is to allow + links on month/day views to never be 404s by never providing a date + that'll be invalid for the given view. + + This is a bit complicated since it handles different intervals of time, + hence the coupling to generic_view. + + However in essence the logic comes down to: + + * If allow_empty and allow_future are both true, this is easy: just + return the naive result (just the next/previous day/week/month, + reguardless of object existence.) + + * If allow_empty is true, allow_future is false, and the naive result + isn't in the future, then return it; otherwise return None. + + * If allow_empty is false and allow_future is true, return the next + date *that contains a valid object*, even if it's in the future. If + there are no next objects, return None. + + * If allow_empty is false and allow_future is false, return the next + date that contains a valid object. If that date is in the future, or + if there are no next objects, return None. + + """ + date_field = generic_view.get_date_field() + allow_empty = generic_view.get_allow_empty() + allow_future = generic_view.get_allow_future() + + get_current = getattr(generic_view, '_get_current_%s' % period) + get_next = getattr(generic_view, '_get_next_%s' % period) + + # Bounds of the current interval + start, end = get_current(date), get_next(date) + + # If allow_empty is True, the naive result will be valid + if allow_empty: + if is_previous: + result = get_current(start - datetime.timedelta(days=1)) + else: + result = end + + if allow_future or result <= timezone_today(): + return result + else: + return None + + # Otherwise, we'll need to go to the database to look for an object + # whose date_field is at least (greater than/less than) the given + # naive result + else: + # Construct a lookup and an ordering depending on whether we're doing + # a previous date or a next date lookup. + if is_previous: + lookup = {'%s__lt' % date_field: generic_view._make_date_lookup_arg(start)} + ordering = '-%s' % date_field + else: + lookup = {'%s__gte' % date_field: generic_view._make_date_lookup_arg(end)} + ordering = date_field + + # Filter out objects in the future if appropriate. + if not allow_future: + # Fortunately, to match the implementation of allow_future, + # we need __lte, which doesn't conflict with __lt above. + if generic_view.uses_datetime_field: + now = timezone.now() + else: + now = timezone_today() + lookup['%s__lte' % date_field] = now + + qs = generic_view.get_queryset().filter(**lookup).order_by(ordering) + + # Snag the first object from the queryset; if it doesn't exist that + # means there's no next/previous link available. + try: + result = getattr(qs[0], date_field) + except IndexError: + return None + + # Convert datetimes to dates in the current time zone. + if generic_view.uses_datetime_field: + if settings.USE_TZ: + result = timezone.localtime(result) + result = result.date() + + # Return the first day of the period. + return get_current(result) + + +def timezone_today(): + """ + Return the current date in the current time zone. + """ + if settings.USE_TZ: + return timezone.localtime(timezone.now()).date() + else: + return datetime.date.today() diff --git a/lib/python2.7/site-packages/django/views/generic/detail.py b/lib/python2.7/site-packages/django/views/generic/detail.py new file mode 100644 index 0000000..180da30 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/generic/detail.py @@ -0,0 +1,173 @@ +from __future__ import unicode_literals + +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.db import models +from django.http import Http404 +from django.utils.translation import ugettext as _ +from django.views.generic.base import TemplateResponseMixin, ContextMixin, View + + +class SingleObjectMixin(ContextMixin): + """ + Provides the ability to retrieve a single object for further manipulation. + """ + model = None + queryset = None + slug_field = 'slug' + context_object_name = None + slug_url_kwarg = 'slug' + pk_url_kwarg = 'pk' + + def get_object(self, queryset=None): + """ + Returns the object the view is displaying. + + By default this requires `self.queryset` and a `pk` or `slug` argument + in the URLconf, but subclasses can override this to return any object. + """ + # Use a custom queryset if provided; this is required for subclasses + # like DateDetailView + if queryset is None: + queryset = self.get_queryset() + + # Next, try looking up by primary key. + pk = self.kwargs.get(self.pk_url_kwarg, None) + slug = self.kwargs.get(self.slug_url_kwarg, None) + if pk is not None: + queryset = queryset.filter(pk=pk) + + # Next, try looking up by slug. + elif slug is not None: + slug_field = self.get_slug_field() + queryset = queryset.filter(**{slug_field: slug}) + + # If none of those are defined, it's an error. + else: + raise AttributeError("Generic detail view %s must be called with " + "either an object pk or a slug." + % self.__class__.__name__) + + try: + # Get the single item from the filtered queryset + obj = queryset.get() + except ObjectDoesNotExist: + raise Http404(_("No %(verbose_name)s found matching the query") % + {'verbose_name': queryset.model._meta.verbose_name}) + return obj + + def get_queryset(self): + """ + Get the queryset to look an object up against. May not be called if + `get_object` is overridden. + """ + if self.queryset is None: + if self.model: + return self.model._default_manager.all() + else: + raise ImproperlyConfigured("%(cls)s is missing a queryset. Define " + "%(cls)s.model, %(cls)s.queryset, or override " + "%(cls)s.get_queryset()." % { + 'cls': self.__class__.__name__ + }) + return self.queryset._clone() + + def get_slug_field(self): + """ + Get the name of a slug field to be used to look up by slug. + """ + return self.slug_field + + def get_context_object_name(self, obj): + """ + Get the name to use for the object. + """ + if self.context_object_name: + return self.context_object_name + elif isinstance(obj, models.Model): + return obj._meta.model_name + else: + return None + + def get_context_data(self, **kwargs): + """ + Insert the single object into the context dict. + """ + context = {} + if self.object: + context['object'] = self.object + context_object_name = self.get_context_object_name(self.object) + if context_object_name: + context[context_object_name] = self.object + context.update(kwargs) + return super(SingleObjectMixin, self).get_context_data(**context) + + +class BaseDetailView(SingleObjectMixin, View): + """ + A base view for displaying a single object + """ + def get(self, request, *args, **kwargs): + self.object = self.get_object() + context = self.get_context_data(object=self.object) + return self.render_to_response(context) + + +class SingleObjectTemplateResponseMixin(TemplateResponseMixin): + template_name_field = None + template_name_suffix = '_detail' + + def get_template_names(self): + """ + Return a list of template names to be used for the request. May not be + called if render_to_response is overridden. Returns the following list: + + * the value of ``template_name`` on the view (if provided) + * the contents of the ``template_name_field`` field on the + object instance that the view is operating upon (if available) + * ``<app_label>/<model_name><template_name_suffix>.html`` + """ + try: + names = super(SingleObjectTemplateResponseMixin, self).get_template_names() + except ImproperlyConfigured: + # If template_name isn't specified, it's not a problem -- + # we just start with an empty list. + names = [] + + # If self.template_name_field is set, grab the value of the field + # of that name from the object; this is the most specific template + # name, if given. + if self.object and self.template_name_field: + name = getattr(self.object, self.template_name_field, None) + if name: + names.insert(0, name) + + # The least-specific option is the default <app>/<model>_detail.html; + # only use this if the object in question is a model. + if isinstance(self.object, models.Model): + names.append("%s/%s%s.html" % ( + self.object._meta.app_label, + self.object._meta.model_name, + self.template_name_suffix + )) + elif hasattr(self, 'model') and self.model is not None and issubclass(self.model, models.Model): + names.append("%s/%s%s.html" % ( + self.model._meta.app_label, + self.model._meta.model_name, + self.template_name_suffix + )) + + # If we still haven't managed to find any template names, we should + # re-raise the ImproperlyConfigured to alert the user. + if not names: + raise + + return names + + +class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView): + """ + Render a "detail" view of an object. + + By default this is a model instance looked up from `self.queryset`, but the + view will support display of *any* object by overriding `self.get_object()`. + """ diff --git a/lib/python2.7/site-packages/django/views/generic/edit.py b/lib/python2.7/site-packages/django/views/generic/edit.py new file mode 100644 index 0000000..fccacf0 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/generic/edit.py @@ -0,0 +1,280 @@ +import warnings + +from django.forms import models as model_forms +from django.core.exceptions import ImproperlyConfigured +from django.http import HttpResponseRedirect +from django.utils.encoding import force_text +from django.views.generic.base import TemplateResponseMixin, ContextMixin, View +from django.views.generic.detail import (SingleObjectMixin, + SingleObjectTemplateResponseMixin, BaseDetailView) + + +class FormMixin(ContextMixin): + """ + A mixin that provides a way to show and handle a form in a request. + """ + + initial = {} + form_class = None + success_url = None + prefix = None + + def get_initial(self): + """ + Returns the initial data to use for forms on this view. + """ + return self.initial.copy() + + def get_prefix(self): + """ + Returns the prefix to use for forms on this view + """ + return self.prefix + + def get_form_class(self): + """ + Returns the form class to use in this view + """ + return self.form_class + + def get_form(self, form_class): + """ + Returns an instance of the form to be used in this view. + """ + return form_class(**self.get_form_kwargs()) + + def get_form_kwargs(self): + """ + Returns the keyword arguments for instantiating the form. + """ + kwargs = { + 'initial': self.get_initial(), + 'prefix': self.get_prefix(), + } + + if self.request.method in ('POST', 'PUT'): + kwargs.update({ + 'data': self.request.POST, + 'files': self.request.FILES, + }) + return kwargs + + def get_success_url(self): + """ + Returns the supplied success URL. + """ + if self.success_url: + # Forcing possible reverse_lazy evaluation + url = force_text(self.success_url) + else: + raise ImproperlyConfigured( + "No URL to redirect to. Provide a success_url.") + return url + + def form_valid(self, form): + """ + If the form is valid, redirect to the supplied URL. + """ + return HttpResponseRedirect(self.get_success_url()) + + def form_invalid(self, form): + """ + If the form is invalid, re-render the context data with the + data-filled form and errors. + """ + return self.render_to_response(self.get_context_data(form=form)) + + +class ModelFormMixin(FormMixin, SingleObjectMixin): + """ + A mixin that provides a way to show and handle a modelform in a request. + """ + fields = None + + def get_form_class(self): + """ + Returns the form class to use in this view. + """ + if self.form_class: + return self.form_class + else: + if self.model is not None: + # If a model has been explicitly provided, use it + model = self.model + elif hasattr(self, 'object') and self.object is not None: + # If this view is operating on a single object, use + # the class of that object + model = self.object.__class__ + else: + # Try to get a queryset and extract the model class + # from that + model = self.get_queryset().model + + if self.fields is None: + warnings.warn("Using ModelFormMixin (base class of %s) without " + "the 'fields' attribute is deprecated." % self.__class__.__name__, + PendingDeprecationWarning) + + return model_forms.modelform_factory(model, fields=self.fields) + + def get_form_kwargs(self): + """ + Returns the keyword arguments for instantiating the form. + """ + kwargs = super(ModelFormMixin, self).get_form_kwargs() + kwargs.update({'instance': self.object}) + return kwargs + + def get_success_url(self): + """ + Returns the supplied URL. + """ + if self.success_url: + url = self.success_url % self.object.__dict__ + else: + try: + url = self.object.get_absolute_url() + except AttributeError: + raise ImproperlyConfigured( + "No URL to redirect to. Either provide a url or define" + " a get_absolute_url method on the Model.") + return url + + def form_valid(self, form): + """ + If the form is valid, save the associated model. + """ + self.object = form.save() + return super(ModelFormMixin, self).form_valid(form) + + +class ProcessFormView(View): + """ + A mixin that renders a form on GET and processes it on POST. + """ + def get(self, request, *args, **kwargs): + """ + Handles GET requests and instantiates a blank version of the form. + """ + form_class = self.get_form_class() + form = self.get_form(form_class) + return self.render_to_response(self.get_context_data(form=form)) + + def post(self, request, *args, **kwargs): + """ + Handles POST requests, instantiating a form instance with the passed + POST variables and then checked for validity. + """ + form_class = self.get_form_class() + form = self.get_form(form_class) + if form.is_valid(): + return self.form_valid(form) + else: + return self.form_invalid(form) + + # PUT is a valid HTTP verb for creating (with a known URL) or editing an + # object, note that browsers only support POST for now. + def put(self, *args, **kwargs): + return self.post(*args, **kwargs) + + +class BaseFormView(FormMixin, ProcessFormView): + """ + A base view for displaying a form + """ + + +class FormView(TemplateResponseMixin, BaseFormView): + """ + A view for displaying a form, and rendering a template response. + """ + + +class BaseCreateView(ModelFormMixin, ProcessFormView): + """ + Base view for creating an new object instance. + + Using this base class requires subclassing to provide a response mixin. + """ + def get(self, request, *args, **kwargs): + self.object = None + return super(BaseCreateView, self).get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + self.object = None + return super(BaseCreateView, self).post(request, *args, **kwargs) + + +class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView): + """ + View for creating a new object instance, + with a response rendered by template. + """ + template_name_suffix = '_form' + + +class BaseUpdateView(ModelFormMixin, ProcessFormView): + """ + Base view for updating an existing object. + + Using this base class requires subclassing to provide a response mixin. + """ + def get(self, request, *args, **kwargs): + self.object = self.get_object() + return super(BaseUpdateView, self).get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + self.object = self.get_object() + return super(BaseUpdateView, self).post(request, *args, **kwargs) + + +class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView): + """ + View for updating an object, + with a response rendered by template. + """ + template_name_suffix = '_form' + + +class DeletionMixin(object): + """ + A mixin providing the ability to delete objects + """ + success_url = None + + def delete(self, request, *args, **kwargs): + """ + Calls the delete() method on the fetched object and then + redirects to the success URL. + """ + self.object = self.get_object() + success_url = self.get_success_url() + self.object.delete() + return HttpResponseRedirect(success_url) + + # Add support for browsers which only accept GET and POST for now. + def post(self, request, *args, **kwargs): + return self.delete(request, *args, **kwargs) + + def get_success_url(self): + if self.success_url: + return self.success_url % self.object.__dict__ + else: + raise ImproperlyConfigured( + "No URL to redirect to. Provide a success_url.") + + +class BaseDeleteView(DeletionMixin, BaseDetailView): + """ + Base view for deleting an object. + + Using this base class requires subclassing to provide a response mixin. + """ + + +class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView): + """ + View for deleting an object retrieved with `self.get_object()`, + with a response rendered by template. + """ + template_name_suffix = '_confirm_delete' diff --git a/lib/python2.7/site-packages/django/views/generic/list.py b/lib/python2.7/site-packages/django/views/generic/list.py new file mode 100644 index 0000000..1aff345 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/generic/list.py @@ -0,0 +1,189 @@ +from __future__ import unicode_literals + +from django.core.paginator import Paginator, InvalidPage +from django.core.exceptions import ImproperlyConfigured +from django.http import Http404 +from django.utils.translation import ugettext as _ +from django.views.generic.base import TemplateResponseMixin, ContextMixin, View + + +class MultipleObjectMixin(ContextMixin): + """ + A mixin for views manipulating multiple objects. + """ + allow_empty = True + queryset = None + model = None + paginate_by = None + paginate_orphans = 0 + context_object_name = None + paginator_class = Paginator + page_kwarg = 'page' + + def get_queryset(self): + """ + Get the list of items for this view. This must be an iterable, and may + be a queryset (in which qs-specific behavior will be enabled). + """ + if self.queryset is not None: + queryset = self.queryset + if hasattr(queryset, '_clone'): + queryset = queryset._clone() + elif self.model is not None: + queryset = self.model._default_manager.all() + else: + raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'" + % self.__class__.__name__) + return queryset + + def paginate_queryset(self, queryset, page_size): + """ + Paginate the queryset, if needed. + """ + paginator = self.get_paginator( + queryset, page_size, orphans=self.get_paginate_orphans(), + allow_empty_first_page=self.get_allow_empty()) + page_kwarg = self.page_kwarg + page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1 + try: + page_number = int(page) + except ValueError: + if page == 'last': + page_number = paginator.num_pages + else: + raise Http404(_("Page is not 'last', nor can it be converted to an int.")) + try: + page = paginator.page(page_number) + return (paginator, page, page.object_list, page.has_other_pages()) + except InvalidPage as e: + raise Http404(_('Invalid page (%(page_number)s): %(message)s') % { + 'page_number': page_number, + 'message': str(e) + }) + + def get_paginate_by(self, queryset): + """ + Get the number of items to paginate by, or ``None`` for no pagination. + """ + return self.paginate_by + + def get_paginator(self, queryset, per_page, orphans=0, + allow_empty_first_page=True, **kwargs): + """ + Return an instance of the paginator for this view. + """ + return self.paginator_class( + queryset, per_page, orphans=orphans, + allow_empty_first_page=allow_empty_first_page, **kwargs) + + def get_paginate_orphans(self): + """ + Returns the maximum number of orphans extend the last page by when + paginating. + """ + return self.paginate_orphans + + def get_allow_empty(self): + """ + Returns ``True`` if the view should display empty lists, and ``False`` + if a 404 should be raised instead. + """ + return self.allow_empty + + def get_context_object_name(self, object_list): + """ + Get the name of the item to be used in the context. + """ + if self.context_object_name: + return self.context_object_name + elif hasattr(object_list, 'model'): + return '%s_list' % object_list.model._meta.model_name + else: + return None + + def get_context_data(self, **kwargs): + """ + Get the context for this view. + """ + queryset = kwargs.pop('object_list', self.object_list) + page_size = self.get_paginate_by(queryset) + context_object_name = self.get_context_object_name(queryset) + if page_size: + paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size) + context = { + 'paginator': paginator, + 'page_obj': page, + 'is_paginated': is_paginated, + 'object_list': queryset + } + else: + context = { + 'paginator': None, + 'page_obj': None, + 'is_paginated': False, + 'object_list': queryset + } + if context_object_name is not None: + context[context_object_name] = queryset + context.update(kwargs) + return super(MultipleObjectMixin, self).get_context_data(**context) + + +class BaseListView(MultipleObjectMixin, View): + """ + A base view for displaying a list of objects. + """ + def get(self, request, *args, **kwargs): + self.object_list = self.get_queryset() + allow_empty = self.get_allow_empty() + + if not allow_empty: + # When pagination is enabled and object_list is a queryset, + # it's better to do a cheap query than to load the unpaginated + # queryset in memory. + if (self.get_paginate_by(self.object_list) is not None + and hasattr(self.object_list, 'exists')): + is_empty = not self.object_list.exists() + else: + is_empty = len(self.object_list) == 0 + if is_empty: + raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.") + % {'class_name': self.__class__.__name__}) + context = self.get_context_data() + return self.render_to_response(context) + + +class MultipleObjectTemplateResponseMixin(TemplateResponseMixin): + """ + Mixin for responding with a template and list of objects. + """ + template_name_suffix = '_list' + + def get_template_names(self): + """ + Return a list of template names to be used for the request. Must return + a list. May not be called if render_to_response is overridden. + """ + try: + names = super(MultipleObjectTemplateResponseMixin, self).get_template_names() + except ImproperlyConfigured: + # If template_name isn't specified, it's not a problem -- + # we just start with an empty list. + names = [] + + # If the list is a queryset, we'll invent a template name based on the + # app and model name. This name gets put at the end of the template + # name list so that user-supplied names override the automatically- + # generated ones. + if hasattr(self.object_list, 'model'): + opts = self.object_list.model._meta + names.append("%s/%s%s.html" % (opts.app_label, opts.model_name, self.template_name_suffix)) + + return names + + +class ListView(MultipleObjectTemplateResponseMixin, BaseListView): + """ + Render some list of objects, set by `self.model` or `self.queryset`. + `self.queryset` can actually be any iterable of items, not just a queryset. + """ diff --git a/lib/python2.7/site-packages/django/views/i18n.py b/lib/python2.7/site-packages/django/views/i18n.py new file mode 100644 index 0000000..f854447 --- /dev/null +++ b/lib/python2.7/site-packages/django/views/i18n.py @@ -0,0 +1,305 @@ +import json +import os +import gettext as gettext_module + +from django import http +from django.conf import settings +from django.template import Context, Template +from django.utils import importlib +from django.utils.translation import check_for_language, to_locale, get_language +from django.utils.encoding import smart_text +from django.utils.formats import get_format_modules, get_format +from django.utils._os import upath +from django.utils.http import is_safe_url +from django.utils import six + +def set_language(request): + """ + Redirect to a given url while setting the chosen language in the + session or cookie. The url and the language code need to be + specified in the request parameters. + + Since this view changes how the user will see the rest of the site, it must + only be accessed as a POST request. If called as a GET request, it will + redirect to the page in the request (the 'next' parameter) without changing + any state. + """ + next = request.REQUEST.get('next') + if not is_safe_url(url=next, host=request.get_host()): + next = request.META.get('HTTP_REFERER') + if not is_safe_url(url=next, host=request.get_host()): + next = '/' + response = http.HttpResponseRedirect(next) + if request.method == 'POST': + lang_code = request.POST.get('language', None) + if lang_code and check_for_language(lang_code): + if hasattr(request, 'session'): + request.session['django_language'] = lang_code + else: + response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code) + return response + + +def get_formats(): + """ + Returns all formats strings required for i18n to work + """ + FORMAT_SETTINGS = ( + 'DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT', + 'YEAR_MONTH_FORMAT', 'MONTH_DAY_FORMAT', 'SHORT_DATE_FORMAT', + 'SHORT_DATETIME_FORMAT', 'FIRST_DAY_OF_WEEK', 'DECIMAL_SEPARATOR', + 'THOUSAND_SEPARATOR', 'NUMBER_GROUPING', + 'DATE_INPUT_FORMATS', 'TIME_INPUT_FORMATS', 'DATETIME_INPUT_FORMATS' + ) + result = {} + for module in [settings] + get_format_modules(reverse=True): + for attr in FORMAT_SETTINGS: + result[attr] = get_format(attr) + formats = {} + for k, v in result.items(): + if isinstance(v, (six.string_types, int)): + formats[k] = smart_text(v) + elif isinstance(v, (tuple, list)): + formats[k] = [smart_text(value) for value in v] + return formats + + +js_catalog_template = r""" +{% autoescape off %} +(function (globals) { + + var django = globals.django || (globals.django = {}); + + {% if plural %} + django.pluralidx = function (n) { + var v={{ plural }}; + if (typeof(v) == 'boolean') { + return v ? 1 : 0; + } else { + return v; + } + }; + {% else %} + django.pluralidx = function (count) { return (count == 1) ? 0 : 1; }; + {% endif %} + + {% if catalog_str %} + /* gettext library */ + + django.catalog = {{ catalog_str }}; + + django.gettext = function (msgid) { + var value = django.catalog[msgid]; + if (typeof(value) == 'undefined') { + return msgid; + } else { + return (typeof(value) == 'string') ? value : value[0]; + } + }; + + django.ngettext = function (singular, plural, count) { + var value = django.catalog[singular]; + if (typeof(value) == 'undefined') { + return (count == 1) ? singular : plural; + } else { + return value[django.pluralidx(count)]; + } + }; + + django.gettext_noop = function (msgid) { return msgid; }; + + django.pgettext = function (context, msgid) { + var value = django.gettext(context + '\x04' + msgid); + if (value.indexOf('\x04') != -1) { + value = msgid; + } + return value; + }; + + django.npgettext = function (context, singular, plural, count) { + var value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count); + if (value.indexOf('\x04') != -1) { + value = django.ngettext(singular, plural, count); + } + return value; + }; + {% else %} + /* gettext identity library */ + + django.gettext = function (msgid) { return msgid; }; + django.ngettext = function (singular, plural, count) { return (count == 1) ? singular : plural; }; + django.gettext_noop = function (msgid) { return msgid; }; + django.pgettext = function (context, msgid) { return msgid; }; + django.npgettext = function (context, singular, plural, count) { return (count == 1) ? singular : plural; }; + {% endif %} + + django.interpolate = function (fmt, obj, named) { + if (named) { + return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); + } else { + return fmt.replace(/%s/g, function(match){return String(obj.shift())}); + } + }; + + + /* formatting library */ + + django.formats = {{ formats_str }}; + + django.get_format = function (format_type) { + var value = django.formats[format_type]; + if (typeof(value) == 'undefined') { + return format_type; + } else { + return value; + } + }; + + /* add to global namespace */ + globals.pluralidx = django.pluralidx; + globals.gettext = django.gettext; + globals.ngettext = django.ngettext; + globals.gettext_noop = django.gettext_noop; + globals.pgettext = django.pgettext; + globals.npgettext = django.npgettext; + globals.interpolate = django.interpolate; + globals.get_format = django.get_format; + +}(this)); +{% endautoescape %} +""" + + +def render_javascript_catalog(catalog=None, plural=None): + template = Template(js_catalog_template) + indent = lambda s: s.replace('\n', '\n ') + context = Context({ + 'catalog_str': indent(json.dumps( + catalog, sort_keys=True, indent=2)) if catalog else None, + 'formats_str': indent(json.dumps( + get_formats(), sort_keys=True, indent=2)), + 'plural': plural, + }) + + return http.HttpResponse(template.render(context), 'text/javascript') + + +def get_javascript_catalog(locale, domain, packages): + default_locale = to_locale(settings.LANGUAGE_CODE) + packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS] + t = {} + paths = [] + en_selected = locale.startswith('en') + en_catalog_missing = True + # paths of requested packages + for package in packages: + p = importlib.import_module(package) + path = os.path.join(os.path.dirname(upath(p.__file__)), 'locale') + paths.append(path) + # add the filesystem paths listed in the LOCALE_PATHS setting + paths.extend(list(reversed(settings.LOCALE_PATHS))) + # first load all english languages files for defaults + for path in paths: + try: + catalog = gettext_module.translation(domain, path, ['en']) + t.update(catalog._catalog) + except IOError: + pass + else: + # 'en' is the selected language and at least one of the packages + # listed in `packages` has an 'en' catalog + if en_selected: + en_catalog_missing = False + # next load the settings.LANGUAGE_CODE translations if it isn't english + if default_locale != 'en': + for path in paths: + try: + catalog = gettext_module.translation(domain, path, [default_locale]) + except IOError: + catalog = None + if catalog is not None: + t.update(catalog._catalog) + # last load the currently selected language, if it isn't identical to the default. + if locale != default_locale: + # If the currently selected language is English but it doesn't have a + # translation catalog (presumably due to being the language translated + # from) then a wrong language catalog might have been loaded in the + # previous step. It needs to be discarded. + if en_selected and en_catalog_missing: + t = {} + else: + locale_t = {} + for path in paths: + try: + catalog = gettext_module.translation(domain, path, [locale]) + except IOError: + catalog = None + if catalog is not None: + locale_t.update(catalog._catalog) + if locale_t: + t = locale_t + plural = None + if '' in t: + for l in t[''].split('\n'): + if l.startswith('Plural-Forms:'): + plural = l.split(':', 1)[1].strip() + if plural is not None: + # this should actually be a compiled function of a typical plural-form: + # Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; + plural = [el.strip() for el in plural.split(';') if el.strip().startswith('plural=')][0].split('=', 1)[1] + + pdict = {} + maxcnts = {} + catalog = {} + for k, v in t.items(): + if k == '': + continue + if isinstance(k, six.string_types): + catalog[k] = v + elif isinstance(k, tuple): + msgid = k[0] + cnt = k[1] + maxcnts[msgid] = max(cnt, maxcnts.get(msgid, 0)) + pdict.setdefault(msgid, {})[cnt] = v + else: + raise TypeError(k) + for k, v in pdict.items(): + catalog[k] = [v.get(i, '') for i in range(maxcnts[msgid] + 1)] + + return catalog, plural + + +def null_javascript_catalog(request, domain=None, packages=None): + """ + Returns "identity" versions of the JavaScript i18n functions -- i.e., + versions that don't actually do anything. + """ + return render_javascript_catalog() + + +def javascript_catalog(request, domain='djangojs', packages=None): + """ + Returns the selected language catalog as a javascript library. + + Receives the list of packages to check for translations in the + packages parameter either from an infodict or as a +-delimited + string from the request. Default is 'django.conf'. + + Additionally you can override the gettext domain for this view, + but usually you don't want to do that, as JavaScript messages + go to the djangojs domain. But this might be needed if you + deliver your JavaScript source from Django templates. + """ + locale = to_locale(get_language()) + + if request.GET and 'language' in request.GET: + if check_for_language(request.GET['language']): + locale = to_locale(request.GET['language']) + + if packages is None: + packages = ['django.conf'] + if isinstance(packages, six.string_types): + packages = packages.split('+') + + catalog, plural = get_javascript_catalog(locale, domain, packages) + return render_javascript_catalog(catalog, plural) diff --git a/lib/python2.7/site-packages/django/views/static.py b/lib/python2.7/site-packages/django/views/static.py new file mode 100644 index 0000000..c1baacd --- /dev/null +++ b/lib/python2.7/site-packages/django/views/static.py @@ -0,0 +1,143 @@ +""" +Views and functions for serving static files. These are only to be used +during development, and SHOULD NOT be used in a production setting. +""" +from __future__ import unicode_literals + +import mimetypes +import os +import stat +import posixpath +import re + +from django.http import (CompatibleStreamingHttpResponse, Http404, + HttpResponse, HttpResponseRedirect, HttpResponseNotModified) +from django.template import loader, Template, Context, TemplateDoesNotExist +from django.utils.http import http_date, parse_http_date +from django.utils.six.moves.urllib.parse import unquote +from django.utils.translation import ugettext as _, ugettext_noop + +def serve(request, path, document_root=None, show_indexes=False): + """ + Serve static files below a given point in the directory structure. + + To use, put a URL pattern such as:: + + (r'^(?P<path>.*)$', 'django.views.static.serve', {'document_root' : '/path/to/my/files/'}) + + in your URLconf. You must provide the ``document_root`` param. You may + also set ``show_indexes`` to ``True`` if you'd like to serve a basic index + of the directory. This index view will use the template hardcoded below, + but if you'd like to override it, you can create a template called + ``static/directory_index.html``. + """ + path = posixpath.normpath(unquote(path)) + path = path.lstrip('/') + newpath = '' + for part in path.split('/'): + if not part: + # Strip empty path components. + continue + drive, part = os.path.splitdrive(part) + head, part = os.path.split(part) + if part in (os.curdir, os.pardir): + # Strip '.' and '..' in path. + continue + newpath = os.path.join(newpath, part).replace('\\', '/') + if newpath and path != newpath: + return HttpResponseRedirect(newpath) + fullpath = os.path.join(document_root, newpath) + if os.path.isdir(fullpath): + if show_indexes: + return directory_index(newpath, fullpath) + raise Http404(_("Directory indexes are not allowed here.")) + if not os.path.exists(fullpath): + raise Http404(_('"%(path)s" does not exist') % {'path': fullpath}) + # Respect the If-Modified-Since header. + statobj = os.stat(fullpath) + if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), + statobj.st_mtime, statobj.st_size): + return HttpResponseNotModified() + content_type, encoding = mimetypes.guess_type(fullpath) + content_type = content_type or 'application/octet-stream' + response = CompatibleStreamingHttpResponse(open(fullpath, 'rb'), + content_type=content_type) + response["Last-Modified"] = http_date(statobj.st_mtime) + if stat.S_ISREG(statobj.st_mode): + response["Content-Length"] = statobj.st_size + if encoding: + response["Content-Encoding"] = encoding + return response + + +DEFAULT_DIRECTORY_INDEX_TEMPLATE = """ +{% load i18n %} +<!DOCTYPE html> +<html lang="en"> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> + <meta http-equiv="Content-Language" content="en-us" /> + <meta name="robots" content="NONE,NOARCHIVE" /> + <title>{% blocktrans %}Index of {{ directory }}{% endblocktrans %}</title> + </head> + <body> + <h1>{% blocktrans %}Index of {{ directory }}{% endblocktrans %}</h1> + <ul> + {% ifnotequal directory "/" %} + <li><a href="../">../</a></li> + {% endifnotequal %} + {% for f in file_list %} + <li><a href="{{ f|urlencode }}">{{ f }}</a></li> + {% endfor %} + </ul> + </body> +</html> +""" +template_translatable = ugettext_noop("Index of %(directory)s") + +def directory_index(path, fullpath): + try: + t = loader.select_template(['static/directory_index.html', + 'static/directory_index']) + except TemplateDoesNotExist: + t = Template(DEFAULT_DIRECTORY_INDEX_TEMPLATE, name='Default directory index template') + files = [] + for f in os.listdir(fullpath): + if not f.startswith('.'): + if os.path.isdir(os.path.join(fullpath, f)): + f += '/' + files.append(f) + c = Context({ + 'directory' : path + '/', + 'file_list' : files, + }) + return HttpResponse(t.render(c)) + +def was_modified_since(header=None, mtime=0, size=0): + """ + Was something modified since the user last downloaded it? + + header + This is the value of the If-Modified-Since header. If this is None, + I'll just return True. + + mtime + This is the modification time of the item we're talking about. + + size + This is the size of the item we're talking about. + """ + try: + if header is None: + raise ValueError + matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header, + re.IGNORECASE) + header_mtime = parse_http_date(matches.group(1)) + header_len = matches.group(3) + if header_len and int(header_len) != size: + raise ValueError + if int(mtime) > header_mtime: + raise ValueError + except (AttributeError, ValueError, OverflowError): + return True + return False |