Source code for devilry.simplified.utils

""" General purpose utilities used by the simplified API. If any functions here
proves useful outside this module, they should me moved to ``devilry.utils``. """
from django.db.models.fields.related import ForeignKey
from django.db.models.fields import FieldDoesNotExist
from django.db.models import Max, Count
from fieldspec import OneToMany


def get_clspath(cls):
    return '{0}.{1}'.format(cls.__module__, cls.__name__)

def get_field_from_fieldname(modelcls, fieldname, fkfield_as_idfield=False):
    def _recurse_get_modelfield(modelcls, path):
        pathseg = path.pop(0)
        field = modelcls._meta.get_field_by_name(pathseg)[0]
        if isinstance(field, ForeignKey):
            parentmodel = field.related.parent_model
            if len(path) == 0:
                if fkfield_as_idfield:
                    return _recurse_get_modelfield(parentmodel, ['id'])
                return field
            return _recurse_get_modelfield(parentmodel, path)
        else:
            return field
    if isinstance(fieldname, OneToMany):
        pass
    else:
        return _recurse_get_modelfield(modelcls, fieldname.split('__'))


def _get_instanceattr(instance, fieldname):
    fieldvalue = getattr(instance, fieldname)
    field = instance.__class__._meta.get_field_by_name(fieldname)[0]
    if isinstance(field, ForeignKey):
        if fieldvalue == None: # If the foreign key is null
            return None
        else:
            return fieldvalue.pk
    else:
        return fieldvalue

def _recurse_getmodelattr(instance, path):
    pathseg = path.pop(0)
    try:
        cur = getattr(instance, pathseg)
    except AttributeError:
        # NOTE: Dirty hack to support list results. This is to return
        # multiple candidates
        if repr(type(instance)) == "<class 'django.db.models.fields.related.RelatedManager'>":
            if path:
                # NOTE: Dirty hack to support list results. This is to return
                # multiple candidates__student__username
                return [_recurse_getmodelattr(obj, [pathseg] + path) for obj in instance.all()]
            else:
                # NOTE: Dirty hack to support list results. This is to return
                # multiple candidates__identifier
                return [_get_instanceattr(obj, pathseg) for obj in instance.all()]
        # NOTE: Dirty hack to support list results. This is to return
        # multiple examiners
        if repr(type(instance)) == "<class 'django.db.models.fields.related.ManyRelatedManager'>":
            return [_get_instanceattr(obj, pathseg) for obj in instance.all()]

        return None  # If the foreign relationship we are following is null, we return None
    if not path:
        return _get_instanceattr(instance, pathseg)
    else:
        return _recurse_getmodelattr(cur, path)


[docs]def modelinstance_to_dict(instance, fieldnames): """ Convert the given django model instance into a dict where each fieldname in ``fieldnames`` is a key. :param instance: A django model instance. :param fieldname: List of fieldname names. Can also be foreign keys, such as ``parentnode__parentnode__short_name``, or :class:`devilry.simplified.OneToMany`. """ dct = {} for fieldname in fieldnames: if isinstance(fieldname, OneToMany): onetomany = fieldname dct[onetomany.related_field] = onetomany.as_list(instance) elif "__" in fieldname: path = fieldname.split('__') dct[fieldname] = _recurse_getmodelattr(instance, path) else: try: dct[fieldname] = _get_instanceattr(instance, fieldname) except FieldDoesNotExist: dct[fieldname] = getattr(instance, fieldname) # This is an annotated field (or something is seriously wrong) except AttributeError: # Annotated field continue # If we fail here, it will not work to use this for both read (which does not support annotated fields) and search return dct
[docs]def fix_expected_data_missing_database_fields(test_groups, expected_res, search_res=None): """ For internal test use ONLY. """ for i in xrange(len(test_groups)): group = test_groups[i] deadline = group.get_active_deadline() expected_res[i]['latest_deadline_id'] = deadline.id expected_res[i]['latest_deadline_deadline'] = deadline.deadline expected_res[i]['number_of_deliveries'] = deadline.deliveries.all().count() if deadline.deliveries.all().count() > 0: max_id = deadline.deliveries.aggregate(Max("id")) expected_res[i]['latest_delivery_id'] = deadline.deliveries.filter(id=max_id['id__max'])[0].id #expected_res[i]['latest_delivery_id'] = deadline.deliveries.all()[0].id else: expected_res[i]['latest_delivery_id'] = None