diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 16f5ef3..a57ede6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,8 +16,6 @@ jobs: max-parallel: 2 matrix: include: - - python-version: "2.7" - toxenv: py27-django{1.10,1.11} - python-version: "3.6" toxenv: py36-django{1.10,1.11,2.0,2.1,2.2,3.0} - python-version: "3.7" diff --git a/access/__init__.py b/access/__init__.py index 64ff1e2..18ddfeb 100644 --- a/access/__init__.py +++ b/access/__init__.py @@ -1 +1 @@ -__version__ = "0.1.1b2" +__version__ = "0.1.2b1" diff --git a/access/admin.py b/access/admin.py index 438908b..813207c 100644 --- a/access/admin.py +++ b/access/admin.py @@ -201,7 +201,7 @@ def has_basic_change_permission(self, request, obj=None): if manager.check_changeable(self.model, request) is False: return False if obj: - return bool(manager.apply_changeable(obj.__class__.objects.filter(id=obj.id), request)) + return self._check_request_object_ability(obj, 'changeable', request) return True def has_delete_permission(self, request, obj=None): @@ -209,7 +209,7 @@ def has_delete_permission(self, request, obj=None): if manager.check_deleteable(self.model, request) is False: return False if obj: - return bool(manager.apply_deleteable(obj.__class__.objects.filter(id=obj.id), request)) + return self._check_request_object_ability(obj, 'deleteable', request) return True def has_view_permission(self, request, obj=None): @@ -217,7 +217,7 @@ def has_view_permission(self, request, obj=None): if manager.check_visible(self.model, request) is False: return False if obj: - return bool(manager.apply_visible(obj.__class__.objects.filter(id=obj.id), request)) + return self._check_request_object_ability(obj, 'visible', request) return True def has_module_permission(self, request): @@ -477,6 +477,28 @@ def clean(form): return super(AccessControlMixin, self).get_formset(request, obj=obj, **kw) + def _get_request_ability_cache(self, request): + """ + Returns the request ability cache to avoid twice requests + for individual model instance ability + """ + if not hasattr(request, '--request-ability-cache'): + setattr(request, '--request-ability-cache', {}) + return getattr(request, '--request-ability-cache') + + def _check_request_object_ability(self, obj, ability, request): + """ + Checks and caches individual model instance ability + """ + model_name = '%s.%s' % (obj._meta.app_label, obj._meta.model_name) + pk = obj.pk + perm = self._get_request_ability_cache(request).get((model_name, pk, ability), None) + if perm is None: + manager = AccessManager(obj.__class__) + perm = bool(manager.apply_able(ability, obj.__class__.objects.filter(id=obj.id), request).exists()) + self._get_request_ability_cache(request)[(model_name, pk, ability)] = perm + return perm + class AccessModelAdmin(AccessControlMixin, ModelAdmin): pass diff --git a/access/plugins.py b/access/plugins.py index 52f12bc..80532d5 100644 --- a/access/plugins.py +++ b/access/plugins.py @@ -206,7 +206,6 @@ def check_able(self, ability, model, request): return ret def __getattr__(self, name): - method = None prefix = 'apply_' if name.startswith(prefix): ability = name[len(prefix):]