summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/django/contrib/admin/util.py
diff options
context:
space:
mode:
authorttt2017-05-13 00:29:47 +0530
committerttt2017-05-13 00:29:47 +0530
commit4336f5f06f61de30ae3fa54650fce63a9d5ef5be (patch)
tree23b4ee9b8e8f24bf732acf2f7ad22ed50cdd5670 /lib/python2.7/site-packages/django/contrib/admin/util.py
downloadSBHS-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.py468
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