Source code for adminactions.utils

from __future__ import absolute_import, unicode_literals

import six

from django.db import connections, models, router
from django.db.models.query import QuerySet
from django.utils.encoding import smart_text

from adminactions.compat import get_all_field_names, get_field_by_name


[docs]def clone_instance(instance, fieldnames=None): """ returns a copy of the passed instance. .. warning: All fields are copied, even primary key :param instance: :py:class:`django.db.models.Model` instance :return: :py:class:`django.db.models.Model` instance """ if fieldnames is None: fieldnames = [fld.name for fld in instance._meta.fields] new_kwargs = dict([(name, getattr(instance, name)) for name in fieldnames]) return instance.__class__(**new_kwargs)
# def get_copy_of_instance(instance): # return instance.__class__.objects.get(pk=instance.pk) def get_attr(obj, attr, default=None): """Recursive get object's attribute. May use dot notation. >>> class C(object): pass >>> a = C() >>> a.b = C() >>> a.b.c = 4 >>> get_attr(a, 'b.c') 4 >>> get_attr(a, 'b.c.y', None) >>> get_attr(a, 'b.c.y', 1) 1 """ if '.' not in attr: ret = getattr(obj, attr, default) else: L = attr.split('.') ret = get_attr(getattr(obj, L[0], default), '.'.join(L[1:]), default) if isinstance(ret, BaseException): raise ret return ret def getattr_or_item(obj, name): """ works indifferently on dict or objects, retrieving the 'name' attribute or item :param obj: dict or object :param name: attribute or item name :return: >>> from django.contrib.auth.models import Permission >>> p = Permission(name='perm') >>> d ={'one': 1, 'two': 2} >>> getattr_or_item(d, 'one') 1 >>> print(getattr_or_item(p, 'name')) perm >>> getattr_or_item(dict, "!!!") Traceback (most recent call last): ... AttributeError: type object has no attribute/item '!!!' """ try: ret = get_attr(obj, name, AttributeError()) except AttributeError: try: ret = obj[name] except (KeyError, TypeError): raise AttributeError("%s object has no attribute/item '%s'" % (obj.__class__.__name__, name)) return ret
[docs]def get_field_value(obj, field, usedisplay=True, raw_callable=False): """ returns the field value or field representation if get_FIELD_display exists :param obj: :class:`django.db.models.Model` instance :param field: :class:`django.db.models.Field` instance or ``basestring`` fieldname :param usedisplay: boolean if True return the get_FIELD_display() result :return: field value >>> from django.contrib.auth.models import Permission >>> p = Permission(name='perm') >>> get_field_value(p, 'name') == 'perm' True >>> get_field_value(p, None) Traceback (most recent call last): ... ValueError: Invalid value for parameter `field`: Should be a field name or a Field instance """ if isinstance(field, six.string_types): fieldname = field elif isinstance(field, models.Field): fieldname = field.name else: raise ValueError('Invalid value for parameter `field`: Should be a field name or a Field instance') if usedisplay and hasattr(obj, 'get_%s_display' % fieldname): value = getattr(obj, 'get_%s_display' % fieldname)() else: value = getattr_or_item(obj, fieldname) if hasattr(value, 'all'): value = ';'.join(smart_text(obj) for obj in value.all()) if not raw_callable and callable(value): value = value() if isinstance(value, models.Model): return smart_text(value) # if isinstance(obj, Model): # field = get_field_by_path(obj, fieldname) # if isinstance(field, ForeignKey): # return unicode(value) if isinstance(value, six.string_types): value = smart_text(value) return value
[docs]def get_field_by_path(model, field_path): """ get a Model class or instance and a path to a attribute, returns the field object :param model: :class:`django.db.models.Model` :param field_path: string path to the field :return: :class:`django.db.models.Field` >>> from django.contrib.auth.models import Permission >>> p = Permission(name='perm') >>> get_field_by_path(Permission, 'content_type').name 'content_type' >>> p = Permission(name='perm') >>> get_field_by_path(p, 'content_type.app_label').name 'app_label' """ parts = field_path.split('.') target = parts[0] if target in get_all_field_names(model): field_object, model, direct, m2m = get_field_by_name(model, target) if isinstance(field_object, models.fields.related.ForeignKey): if parts[1:]: return get_field_by_path(field_object.rel.to, '.'.join(parts[1:])) else: return field_object else: return field_object return None
[docs]def get_verbose_name(model_or_queryset, field): """ returns the value of the ``verbose_name`` of a field typically used in the templates where you can have a dynamic queryset :param model_or_queryset: target object :type model_or_queryset: :class:`django.db.models.Model`, :class:`django.db.query.Queryset` :param field: field to get the verbose name :type field: :class:`django.db.models.Field`, basestring :return: translated field verbose name :rtype: unicode Valid uses: >>> from django.contrib.auth.models import User, Permission >>> user = User() >>> p = Permission() >>> get_verbose_name(user, 'username') == 'username' True >>> get_verbose_name(User, 'username') == 'username' True >>> get_verbose_name(User.objects.all(), 'username') == 'username' True >>> get_verbose_name(User.objects, 'username') == 'username' True >>> get_verbose_name(User.objects, user._meta.fields[0]) == 'ID' True >>> get_verbose_name(p, 'content_type.model') == 'python model class name' True """ if isinstance(model_or_queryset, models.Manager): model = model_or_queryset.model elif isinstance(model_or_queryset, QuerySet): model = model_or_queryset.model elif isinstance(model_or_queryset, models.Model): model = model_or_queryset elif type(model_or_queryset) is models.base.ModelBase: model = model_or_queryset else: raise ValueError('`get_verbose_name` expects Manager, Queryset or Model as first parameter (got %s)' % type( model_or_queryset)) if isinstance(field, six.string_types): field = get_field_by_path(model, field) elif isinstance(field, models.Field): field = field else: raise ValueError('`get_verbose_name` field_path must be string or Field class') return field.verbose_name
def flatten(iterable): """ flatten(sequence) -> list Returns a single, flat list which contains all elements retrieved from the sequence and all recursively contained sub-sequences (iterables). :param sequence: any object that implements iterable protocol (see: :ref:`typeiter`) :return: list Examples: >>> from adminactions.utils import flatten >>> [1, 2, [3,4], (5,6)] [1, 2, [3, 4], (5, 6)] >>> flatten([[[1,2,3], (42,None)], [4,5], [6], 7, (8,9,10)]) [1, 2, 3, 42, None, 4, 5, 6, 7, 8, 9, 10]""" result = list() for el in iterable: if hasattr(el, "__iter__") and not isinstance(el, six.string_types): result.extend(flatten(el)) else: result.append(el) return list(result)