Navigation: Related field support to SourceColumn
Add support to the SourceColumn class to resolve related fields using the double underscore as separator. Columns that use related no longer have to use throw away lambdas. Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
@@ -175,6 +175,8 @@
|
||||
- Upgraded from Celery 3.1.26 to 4.1.1. The following settings have been
|
||||
renamed: CELERY_ALWAYS_EAGER to CELERY_TASK_ALWAYS_EAGER,
|
||||
BROKER_URL to CELERY_BROKER_URL.
|
||||
- Internal change. Add support to the SourceColumn class to resolve
|
||||
related fields using the double underscore as separator.
|
||||
|
||||
3.1.9 (2018-11-01)
|
||||
==================
|
||||
|
||||
@@ -9,7 +9,7 @@ from django.db.models import Q
|
||||
from django.utils.translation import ugettext
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mayan.apps.common.utils import return_attrib, return_related
|
||||
from mayan.apps.common.utils import resolve_attribute, return_related
|
||||
from mayan.apps.permissions import Permission
|
||||
from mayan.apps.permissions.models import StoredPermission
|
||||
|
||||
@@ -46,7 +46,7 @@ class AccessControlListManager(models.Manager):
|
||||
stored_permissions = (permissions.stored_permission,)
|
||||
|
||||
if related:
|
||||
obj = return_attrib(obj, related)
|
||||
obj = resolve_attribute(obj, related)
|
||||
|
||||
try:
|
||||
parent_accessor = ModelPermission.get_inheritance(
|
||||
@@ -199,7 +199,7 @@ class AccessControlListManager(models.Manager):
|
||||
return StoredPermission.objects.none()
|
||||
else:
|
||||
try:
|
||||
parent_object = return_attrib(
|
||||
parent_object = resolve_attribute(
|
||||
obj=instance, attrib=parent_accessor
|
||||
)
|
||||
except AttributeError:
|
||||
|
||||
@@ -11,7 +11,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .classes import Package
|
||||
from .models import UserLocaleProfile
|
||||
from .utils import return_attrib
|
||||
from .utils import resolve_attribute
|
||||
from .widgets import DisableableSelectWidget, PlainWidget, TextAreaDiv
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class DetailForm(forms.ModelForm):
|
||||
super(DetailForm, self).__init__(*args, **kwargs)
|
||||
|
||||
for extra_field in self.extra_fields:
|
||||
result = return_attrib(self.instance, extra_field['field'])
|
||||
result = resolve_attribute(self.instance, 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):
|
||||
@@ -53,7 +53,7 @@ class DetailForm(forms.ModelForm):
|
||||
else:
|
||||
self.fields[extra_field['field']] = forms.CharField(
|
||||
label=extra_field['label'],
|
||||
initial=return_attrib(
|
||||
initial=resolve_attribute(
|
||||
self.instance,
|
||||
extra_field['field'], None
|
||||
),
|
||||
|
||||
@@ -10,7 +10,7 @@ import mayan
|
||||
|
||||
from ..classes import Collection, Dashboard
|
||||
from ..literals import MESSAGE_SQLITE_WARNING
|
||||
from ..utils import check_for_sqlite, return_attrib
|
||||
from ..utils import check_for_sqlite, resolve_attribute
|
||||
|
||||
register = Library()
|
||||
|
||||
@@ -30,7 +30,7 @@ def get_collections():
|
||||
def get_encoded_parameter(item, parameters_dict):
|
||||
result = {}
|
||||
for attrib_name, attrib in parameters_dict.items():
|
||||
result[attrib_name] = return_attrib(item, attrib)
|
||||
result[attrib_name] = resolve_attribute(item, attrib)
|
||||
return dumps(result)
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ def get_type(value):
|
||||
|
||||
@register.filter
|
||||
def object_property(value, arg):
|
||||
return return_attrib(value, arg)
|
||||
return resolve_attribute(value, arg)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
|
||||
@@ -7,6 +7,7 @@ import tempfile
|
||||
import types
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.urls import resolve as django_resolve
|
||||
from django.urls.base import get_script_prefix
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
@@ -129,27 +130,34 @@ def resolve(path, urlconf=None):
|
||||
return django_resolve(path=path, urlconf=urlconf)
|
||||
|
||||
|
||||
def return_attrib(obj, attrib, arguments=None):
|
||||
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):
|
||||
elif isinstance(obj, dict_type) or isinstance(obj, dictionary_type):
|
||||
return obj[attrib]
|
||||
else:
|
||||
result = reduce_function(getattr, attrib.split('.'), obj)
|
||||
if isinstance(result, types.MethodType):
|
||||
if arguments:
|
||||
return result(**arguments)
|
||||
try:
|
||||
result = reduce_function(getattr, attrib.split('.'), obj)
|
||||
if isinstance(result, types.MethodType):
|
||||
if arguments:
|
||||
return result(**arguments)
|
||||
else:
|
||||
return result()
|
||||
else:
|
||||
return result()
|
||||
else:
|
||||
return result
|
||||
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
|
||||
|
||||
|
||||
def return_related(instance, related_field):
|
||||
"""
|
||||
This functions works in a similar method to return_attrib but is
|
||||
This functions works in a similar method to resolve_attribute but is
|
||||
meant for related models. Support multiple levels of relationship
|
||||
using double underscore.
|
||||
"""
|
||||
|
||||
@@ -8,14 +8,15 @@ from furl import furl
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib.admin.utils import label_for_field
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.exceptions import FieldDoesNotExist, PermissionDenied
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.shortcuts import resolve_url
|
||||
from django.template import VariableDoesNotExist, Variable
|
||||
from django.template.defaulttags import URLNode
|
||||
from django.urls import Resolver404, resolve
|
||||
from django.utils.encoding import force_str, force_text
|
||||
|
||||
from mayan.apps.common.utils import return_attrib
|
||||
from mayan.apps.common.utils import resolve_attribute
|
||||
from mayan.apps.permissions import Permission
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -469,6 +470,26 @@ class Separator(Link):
|
||||
class SourceColumn(object):
|
||||
_registry = {}
|
||||
|
||||
@staticmethod
|
||||
def get_attribute_recursive(attribute, model):
|
||||
"""
|
||||
Walk over the double underscore (__) separated path to the last
|
||||
field. Returns the field name and the corresponding model class.
|
||||
Used to introspect the label or short_description of a model's
|
||||
attribute.
|
||||
"""
|
||||
last_model = model
|
||||
for part in attribute.split(LOOKUP_SEP):
|
||||
last_model = model
|
||||
try:
|
||||
field = model._meta.get_field(part)
|
||||
except FieldDoesNotExist:
|
||||
break;
|
||||
else:
|
||||
model = field.related_model or field.model
|
||||
|
||||
return part, last_model
|
||||
|
||||
@staticmethod
|
||||
def sort(columns):
|
||||
return sorted(columns, key=lambda x: x.order)
|
||||
@@ -507,11 +528,13 @@ class SourceColumn(object):
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
# TODO: Add support for related fields (dotted or double underscore attributes)
|
||||
if not self._label:
|
||||
if self.attribute:
|
||||
name, model = SourceColumn.get_attribute_recursive(
|
||||
attribute=self.attribute, model=self.source._meta.model
|
||||
)
|
||||
self._label = label_for_field(
|
||||
name=self.attribute, model=self.source._meta.model
|
||||
name=name, model=model
|
||||
)
|
||||
else:
|
||||
self._label = 'Function'
|
||||
@@ -520,7 +543,7 @@ class SourceColumn(object):
|
||||
|
||||
def resolve(self, context):
|
||||
if self.attribute:
|
||||
result = return_attrib(context['object'], self.attribute)
|
||||
result = resolve_attribute(context['object'], self.attribute)
|
||||
elif self.func:
|
||||
result = self.func(context=context)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user