diff --git a/mayan/apps/acls/managers.py b/mayan/apps/acls/managers.py index a4da3a0e85..40a44f653b 100644 --- a/mayan/apps/acls/managers.py +++ b/mayan/apps/acls/managers.py @@ -46,7 +46,7 @@ class AccessControlListManager(models.Manager): stored_permissions = (permissions.stored_permission,) if related: - obj = resolve_attribute(obj, related) + obj = resolve_attribute(obj=obj, attribute=related) try: parent_accessor = ModelPermission.get_inheritance( @@ -200,7 +200,7 @@ class AccessControlListManager(models.Manager): else: try: parent_object = resolve_attribute( - obj=instance, attrib=parent_accessor + obj=instance, attribute=parent_accessor ) except AttributeError: # Parent accessor is not an attribute, try it as a related diff --git a/mayan/apps/common/forms.py b/mayan/apps/common/forms.py index ceb6e61c11..37f566727b 100644 --- a/mayan/apps/common/forms.py +++ b/mayan/apps/common/forms.py @@ -43,7 +43,7 @@ class DetailForm(forms.ModelForm): super(DetailForm, self).__init__(*args, **kwargs) for extra_field in self.extra_fields: - result = resolve_attribute(self.instance, extra_field['field']) + result = resolve_attribute(obj=self.instance, attribute=extra_field['field']) label = 'label' in extra_field and extra_field['label'] or None # TODO: Add others result types <=> Field types if isinstance(result, models.query.QuerySet): @@ -54,8 +54,8 @@ class DetailForm(forms.ModelForm): self.fields[extra_field['field']] = forms.CharField( label=extra_field['label'], initial=resolve_attribute( - self.instance, - extra_field['field'], None + obj=self.instance, + attribute=extra_field['field'] ), widget=extra_field.get('widget', PlainWidget) ) diff --git a/mayan/apps/common/templatetags/common_tags.py b/mayan/apps/common/templatetags/common_tags.py index 71b1606d35..3c50bf2a27 100644 --- a/mayan/apps/common/templatetags/common_tags.py +++ b/mayan/apps/common/templatetags/common_tags.py @@ -32,8 +32,8 @@ def get_collections(): @register.filter def get_encoded_parameter(item, parameters_dict): result = {} - for attrib_name, attrib in parameters_dict.items(): - result[attrib_name] = resolve_attribute(item, attrib) + for key, value in parameters_dict.items(): + result[key] = resolve_attribute(obj=item, attribute=value) return dumps(result) @@ -44,7 +44,7 @@ def get_type(value): @register.filter def object_property(value, arg): - return resolve_attribute(value, arg) + return resolve_attribute(obj=value, attribute=arg) @register.simple_tag diff --git a/mayan/apps/common/utils.py b/mayan/apps/common/utils.py index e931b2c34b..e26fa28575 100644 --- a/mayan/apps/common/utils.py +++ b/mayan/apps/common/utils.py @@ -130,29 +130,37 @@ def resolve(path, urlconf=None): return django_resolve(path=path, urlconf=urlconf) -def resolve_attribute(obj, attrib, arguments=None): - if isinstance(attrib, types.FunctionType): - return attrib(obj) - elif isinstance(obj, dict_type) or isinstance(obj, dictionary_type): - return obj[attrib] - else: +def resolve_attribute(obj, attribute, kwargs=None): + if not kwargs: + kwargs = {} + + # Try as a callable + try: + return attribute(obj, **kwargs) + except TypeError: + # Try as a dictionary try: - result = reduce_function(getattr, attrib.split('.'), obj) - if isinstance(result, types.MethodType): - if arguments: - return result(**arguments) + return obj[attribute] + except TypeError: + try: + # If there are dots in the attribute name, traverse them + # to the final attribute + result = reduce_function(getattr, attribute.split('.'), obj) + try: + # Try it as a method + return result(**kwargs) + except TypeError: + # Try it as a property + return result + except AttributeError: + # Try as a related model field + if LOOKUP_SEP in attribute: + attrib = attribute.replace(LOOKUP_SEP, '.') + return resolve_attribute( + obj=obj, attribute=attribute, kwargs=kwargs + ) else: - return result() - else: - return result - except AttributeError: - if LOOKUP_SEP in attrib: - attrib = attrib.replace(LOOKUP_SEP, '.') - return resolve_attribute( - obj=obj, attrib=attrib, arguments=arguments - ) - else: - raise + raise def return_related(instance, related_field):