diff options
author | ttt | 2017-05-13 00:29:47 +0530 |
---|---|---|
committer | ttt | 2017-05-13 00:29:47 +0530 |
commit | 4336f5f06f61de30ae3fa54650fce63a9d5ef5be (patch) | |
tree | 23b4ee9b8e8f24bf732acf2f7ad22ed50cdd5670 /lib/python2.7/site-packages/django/contrib/admin/util.py | |
download | SBHS-2018-Rpi-4336f5f06f61de30ae3fa54650fce63a9d5ef5be.tar.gz SBHS-2018-Rpi-4336f5f06f61de30ae3fa54650fce63a9d5ef5be.tar.bz2 SBHS-2018-Rpi-4336f5f06f61de30ae3fa54650fce63a9d5ef5be.zip |
added all server files
Diffstat (limited to 'lib/python2.7/site-packages/django/contrib/admin/util.py')
-rw-r--r-- | lib/python2.7/site-packages/django/contrib/admin/util.py | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/contrib/admin/util.py b/lib/python2.7/site-packages/django/contrib/admin/util.py new file mode 100644 index 0000000..177b2da --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/admin/util.py @@ -0,0 +1,468 @@ +from __future__ import unicode_literals + +import datetime +import decimal + +from django.contrib.auth import get_permission_codename +from django.db import models +from django.db.models.constants import LOOKUP_SEP +from django.db.models.deletion import Collector +from django.db.models.related import RelatedObject +from django.forms.forms import pretty_name +from django.utils import formats +from django.utils.html import format_html +from django.utils.text import capfirst +from django.utils import timezone +from django.utils.encoding import force_str, force_text, smart_text +from django.utils import six +from django.utils.translation import ungettext +from django.core.urlresolvers import reverse + +def lookup_needs_distinct(opts, lookup_path): + """ + Returns True if 'distinct()' should be used to query the given lookup path. + """ + field_name = lookup_path.split('__', 1)[0] + field = opts.get_field_by_name(field_name)[0] + if ((hasattr(field, 'rel') and + isinstance(field.rel, models.ManyToManyRel)) or + (isinstance(field, models.related.RelatedObject) and + not field.field.unique)): + return True + return False + +def prepare_lookup_value(key, value): + """ + Returns a lookup value prepared to be used in queryset filtering. + """ + # if key ends with __in, split parameter into separate values + if key.endswith('__in'): + value = value.split(',') + # if key ends with __isnull, special case '' and the string literals 'false' and '0' + if key.endswith('__isnull'): + if value.lower() in ('', 'false', '0'): + value = False + else: + value = True + return value + +def quote(s): + """ + Ensure that primary key values do not confuse the admin URLs by escaping + any '/', '_' and ':' and similarly problematic characters. + Similar to urllib.quote, except that the quoting is slightly different so + that it doesn't get automatically unquoted by the Web browser. + """ + if not isinstance(s, six.string_types): + return s + res = list(s) + for i in range(len(res)): + c = res[i] + if c in """:/_#?;@&=+$,"<>%\\""": + res[i] = '_%02X' % ord(c) + return ''.join(res) + + +def unquote(s): + """ + Undo the effects of quote(). Based heavily on urllib.unquote(). + """ + mychr = chr + myatoi = int + list = s.split('_') + res = [list[0]] + myappend = res.append + del list[0] + for item in list: + if item[1:2]: + try: + myappend(mychr(myatoi(item[:2], 16)) + item[2:]) + except ValueError: + myappend('_' + item) + else: + myappend('_' + item) + return "".join(res) + + +def flatten_fieldsets(fieldsets): + """Returns a list of field names from an admin fieldsets structure.""" + field_names = [] + for name, opts in fieldsets: + for field in opts['fields']: + if isinstance(field, (list, tuple)): + field_names.extend(field) + else: + field_names.append(field) + return field_names + + +def get_deleted_objects(objs, opts, user, admin_site, using): + """ + Find all objects related to ``objs`` that should also be deleted. ``objs`` + must be a homogenous iterable of objects (e.g. a QuerySet). + + Returns a nested list of strings suitable for display in the + template with the ``unordered_list`` filter. + + """ + collector = NestedObjects(using=using) + collector.collect(objs) + perms_needed = set() + + def format_callback(obj): + has_admin = obj.__class__ in admin_site._registry + opts = obj._meta + + if has_admin: + admin_url = reverse('%s:%s_%s_change' + % (admin_site.name, + opts.app_label, + opts.model_name), + None, (quote(obj._get_pk_val()),)) + p = '%s.%s' % (opts.app_label, + get_permission_codename('delete', opts)) + if not user.has_perm(p): + perms_needed.add(opts.verbose_name) + # Display a link to the admin page. + return format_html('{0}: <a href="{1}">{2}</a>', + capfirst(opts.verbose_name), + admin_url, + obj) + else: + # Don't display link to edit, because it either has no + # admin or is edited inline. + return '%s: %s' % (capfirst(opts.verbose_name), + force_text(obj)) + + to_delete = collector.nested(format_callback) + + protected = [format_callback(obj) for obj in collector.protected] + + return to_delete, perms_needed, protected + + +class NestedObjects(Collector): + def __init__(self, *args, **kwargs): + super(NestedObjects, self).__init__(*args, **kwargs) + self.edges = {} # {from_instance: [to_instances]} + self.protected = set() + + def add_edge(self, source, target): + self.edges.setdefault(source, []).append(target) + + def collect(self, objs, source_attr=None, **kwargs): + for obj in objs: + if source_attr: + self.add_edge(getattr(obj, source_attr), obj) + else: + self.add_edge(None, obj) + try: + return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs) + except models.ProtectedError as e: + self.protected.update(e.protected_objects) + + def related_objects(self, related, objs): + qs = super(NestedObjects, self).related_objects(related, objs) + return qs.select_related(related.field.name) + + def _nested(self, obj, seen, format_callback): + if obj in seen: + return [] + seen.add(obj) + children = [] + for child in self.edges.get(obj, ()): + children.extend(self._nested(child, seen, format_callback)) + if format_callback: + ret = [format_callback(obj)] + else: + ret = [obj] + if children: + ret.append(children) + return ret + + def nested(self, format_callback=None): + """ + Return the graph as a nested list. + + """ + seen = set() + roots = [] + for root in self.edges.get(None, ()): + roots.extend(self._nested(root, seen, format_callback)) + return roots + + def can_fast_delete(self, *args, **kwargs): + """ + We always want to load the objects into memory so that we can display + them to the user in confirm page. + """ + return False + + +def model_format_dict(obj): + """ + Return a `dict` with keys 'verbose_name' and 'verbose_name_plural', + typically for use with string formatting. + + `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. + + """ + if isinstance(obj, (models.Model, models.base.ModelBase)): + opts = obj._meta + elif isinstance(obj, models.query.QuerySet): + opts = obj.model._meta + else: + opts = obj + return { + 'verbose_name': force_text(opts.verbose_name), + 'verbose_name_plural': force_text(opts.verbose_name_plural) + } + + +def model_ngettext(obj, n=None): + """ + Return the appropriate `verbose_name` or `verbose_name_plural` value for + `obj` depending on the count `n`. + + `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. + If `obj` is a `QuerySet` instance, `n` is optional and the length of the + `QuerySet` is used. + + """ + if isinstance(obj, models.query.QuerySet): + if n is None: + n = obj.count() + obj = obj.model + d = model_format_dict(obj) + singular, plural = d["verbose_name"], d["verbose_name_plural"] + return ungettext(singular, plural, n or 0) + + +def lookup_field(name, obj, model_admin=None): + opts = obj._meta + try: + f = opts.get_field(name) + except models.FieldDoesNotExist: + # For non-field values, the value is either a method, property or + # returned via a callable. + if callable(name): + attr = name + value = attr(obj) + elif (model_admin is not None and hasattr(model_admin, name) and + not name == '__str__' and not name == '__unicode__'): + attr = getattr(model_admin, name) + value = attr(obj) + else: + attr = getattr(obj, name) + if callable(attr): + value = attr() + else: + value = attr + f = None + else: + attr = None + value = getattr(obj, name) + return f, attr, value + + +def label_for_field(name, model, model_admin=None, return_attr=False): + """ + Returns a sensible label for a field name. The name can be a callable, + property (but not created with @property decorator) or the name of an + object's attribute, as well as a genuine fields. If return_attr is + True, the resolved attribute (which could be a callable) is also returned. + This will be None if (and only if) the name refers to a field. + """ + attr = None + try: + field = model._meta.get_field_by_name(name)[0] + if isinstance(field, RelatedObject): + label = field.opts.verbose_name + else: + label = field.verbose_name + except models.FieldDoesNotExist: + if name == "__unicode__": + label = force_text(model._meta.verbose_name) + attr = six.text_type + elif name == "__str__": + label = force_str(model._meta.verbose_name) + attr = bytes + else: + if callable(name): + attr = name + elif model_admin is not None and hasattr(model_admin, name): + attr = getattr(model_admin, name) + elif hasattr(model, name): + attr = getattr(model, name) + else: + message = "Unable to lookup '%s' on %s" % (name, model._meta.object_name) + if model_admin: + message += " or %s" % (model_admin.__class__.__name__,) + raise AttributeError(message) + + if hasattr(attr, "short_description"): + label = attr.short_description + elif (isinstance(attr, property) and + hasattr(attr, "fget") and + hasattr(attr.fget, "short_description")): + label = attr.fget.short_description + elif callable(attr): + if attr.__name__ == "<lambda>": + label = "--" + else: + label = pretty_name(attr.__name__) + else: + label = pretty_name(name) + if return_attr: + return (label, attr) + else: + return label + + +def help_text_for_field(name, model): + help_text = "" + try: + field_data = model._meta.get_field_by_name(name) + except models.FieldDoesNotExist: + pass + else: + field = field_data[0] + if not isinstance(field, RelatedObject): + help_text = field.help_text + return smart_text(help_text) + + +def display_for_field(value, field): + from django.contrib.admin.templatetags.admin_list import _boolean_icon + from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE + + if field.flatchoices: + return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE) + # NullBooleanField needs special-case null-handling, so it comes + # before the general null test. + elif isinstance(field, models.BooleanField) or isinstance(field, models.NullBooleanField): + return _boolean_icon(value) + elif value is None: + return EMPTY_CHANGELIST_VALUE + elif isinstance(field, models.DateTimeField): + return formats.localize(timezone.template_localtime(value)) + elif isinstance(field, (models.DateField, models.TimeField)): + return formats.localize(value) + elif isinstance(field, models.DecimalField): + return formats.number_format(value, field.decimal_places) + elif isinstance(field, models.FloatField): + return formats.number_format(value) + else: + return smart_text(value) + + +def display_for_value(value, boolean=False): + from django.contrib.admin.templatetags.admin_list import _boolean_icon + from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE + + if boolean: + return _boolean_icon(value) + elif value is None: + return EMPTY_CHANGELIST_VALUE + elif isinstance(value, datetime.datetime): + return formats.localize(timezone.template_localtime(value)) + elif isinstance(value, (datetime.date, datetime.time)): + return formats.localize(value) + elif isinstance(value, six.integer_types + (decimal.Decimal, float)): + return formats.number_format(value) + else: + return smart_text(value) + + +class NotRelationField(Exception): + pass + + +def get_model_from_relation(field): + if hasattr(field, 'get_path_info'): + return field.get_path_info()[-1].to_opts.model + elif isinstance(field, models.related.RelatedObject): + return field.model + elif getattr(field, 'rel'): # or isinstance? + return field.rel.to + else: + raise NotRelationField + + +def reverse_field_path(model, path): + """ Create a reversed field path. + + E.g. Given (Order, "user__groups"), + return (Group, "user__order"). + + Final field must be a related model, not a data field. + + """ + reversed_path = [] + parent = model + pieces = path.split(LOOKUP_SEP) + for piece in pieces: + field, model, direct, m2m = parent._meta.get_field_by_name(piece) + # skip trailing data field if extant: + if len(reversed_path) == len(pieces)-1: # final iteration + try: + get_model_from_relation(field) + except NotRelationField: + break + if direct: + related_name = field.related_query_name() + parent = field.rel.to + else: + related_name = field.field.name + parent = field.model + reversed_path.insert(0, related_name) + return (parent, LOOKUP_SEP.join(reversed_path)) + + +def get_fields_from_path(model, path): + """ Return list of Fields given path relative to model. + + e.g. (ModelX, "user__groups__name") -> [ + <django.db.models.fields.related.ForeignKey object at 0x...>, + <django.db.models.fields.related.ManyToManyField object at 0x...>, + <django.db.models.fields.CharField object at 0x...>, + ] + """ + pieces = path.split(LOOKUP_SEP) + fields = [] + for piece in pieces: + if fields: + parent = get_model_from_relation(fields[-1]) + else: + parent = model + fields.append(parent._meta.get_field_by_name(piece)[0]) + return fields + + +def remove_trailing_data_field(fields): + """ Discard trailing non-relation field if extant. """ + try: + get_model_from_relation(fields[-1]) + except NotRelationField: + fields = fields[:-1] + return fields + + +def get_limit_choices_to_from_path(model, path): + """ Return Q object for limiting choices if applicable. + + If final model in path is linked via a ForeignKey or ManyToManyField which + has a `limit_choices_to` attribute, return it as a Q object. + """ + + fields = get_fields_from_path(model, path) + fields = remove_trailing_data_field(fields) + limit_choices_to = ( + fields and hasattr(fields[-1], 'rel') and + getattr(fields[-1].rel, 'limit_choices_to', None)) + if not limit_choices_to: + return models.Q() # empty Q + elif isinstance(limit_choices_to, models.Q): + return limit_choices_to # already a Q + else: + return models.Q(**limit_choices_to) # convert dict to Q |