Repository URL to install this package:
Version:
0.2.0a6 ▾
|
from __future__ import annotations
from dj_kaos.utils.admin import EditReadonlyAdminMixin, ExcludeFromFieldsetsMixin
from dj_kaos.utils.forms import unrequire_form
from dj_kaos.utils.perms import get_permission_descriptor
from django import forms
from django.contrib import admin
from django.contrib.admin.options import BaseModelAdmin
from django.shortcuts import get_object_or_404
from django_object_actions import DjangoObjectActions, BaseDjangoObjectActions
from dj_kaos.contrib.autocomplete_list_filter import AutocompleteListFilterAdminMixin
class BaseKaosModelAdmin(BaseModelAdmin):
"""
Base model admin class used with models that support `model.config` (specifically `KaosModels`) to grab admin
configuration `model.config`. It is the equivalent of `BaseModelAdmin` and inherits from it.
Please keep in mind, for various reasons, this admin does not pull `fields` and `fieldsets` from the model config.
You have to explicitly define these on your admin
"""
extra_readonly_fields = ()
def get_readonly_fields(self, request, obj=None):
if self.readonly_fields != BaseModelAdmin.readonly_fields:
return super().get_readonly_fields(request, obj)
return (
*super().get_readonly_fields(request, obj),
*self.extra_readonly_fields,
*self.model.config.get_readonly_fields(request, obj),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
config = self.model.config
if config.unrequired_fields and self.form is forms.ModelForm:
self.form = unrequire_form(self.model, config.unrequired_fields)
class SimpleKaosModelAdmin(BaseKaosModelAdmin, admin.ModelAdmin):
"""
Simple Admin class used with models that support `model.config` (specifically `KaosModels`) to grab admin
configuration `model.config`.
"""
def get_search_fields(self, request):
if self.search_fields != admin.ModelAdmin.search_fields:
return super().get_search_fields(request)
return self.model.config.get_search_fields(request)
def get_list_display(self, request):
if self.list_display != admin.ModelAdmin.list_display:
return super().get_list_display(request)
return self.model.config.get_list_display(request)
def get_list_filter(self, request):
if self.list_filter != admin.ModelAdmin.list_filter:
return super().get_list_filter(request)
return self.model.config.get_list_filter(request)
def should_include_action(admin, user, obj, action_name):
admin_method = getattr(admin, action_name)
if not user.is_superuser and admin_method:
allowed_permissions = getattr(admin_method, 'allowed_permissions', None)
if allowed_permissions:
for perm_action in allowed_permissions:
if not user.has_perm(get_permission_descriptor(obj._meta, perm_action)):
return False
method = getattr(obj, action_name)
if method:
if not user.is_superuser and not method.check_permissions(user, obj):
return False
if method.exclude(obj):
return False
if not method.include(obj):
return False
return True
class ObjectActionsPermissionsMixin(BaseDjangoObjectActions):
"""
Built on DjangoObjectActions Admin, it checks if the user has change permissions on the object in order to show the
change actions
"""
def get_change_actions(self, request, object_id, form_url, obj=None):
change_actions = super(ObjectActionsPermissionsMixin, self).get_change_actions(request, object_id, form_url)
obj = obj or self._get_change_action_object(object_id)
return tuple(action for action in change_actions if should_include_action(self, request.user, obj, action))
def _get_change_action_object(self, object_id=None):
if object_id and getattr(self, '__obj', None) is None:
self.__obj = get_object_or_404(self.model, pk=object_id)
return self.__obj
class ObjectPermissionsAdminMixin(BaseModelAdmin):
def has_change_permission(self, request, obj=None):
opts = self.opts
return request.user.has_perm(get_permission_descriptor(opts, 'change'), obj)
def has_delete_permission(self, request, obj=None):
opts = self.opts
return request.user.has_perm(get_permission_descriptor(opts, 'delete'), obj)
def has_view_permission(self, request, obj=None):
opts = self.opts
return request.user.has_perm(get_permission_descriptor(opts, 'view'), obj) or self.has_change_permission(
request, obj)
class KaosModelAdmin(
EditReadonlyAdminMixin,
AutocompleteListFilterAdminMixin,
ObjectActionsPermissionsMixin,
DjangoObjectActions,
ExcludeFromFieldsetsMixin,
ObjectPermissionsAdminMixin,
SimpleKaosModelAdmin
):
"""
Admin class used with models that support `model.config` (specifically `KaosModels`) to grab admin
configuration `model.config`.
Please keep in mind, for various reasons, this admin does not pull `fields` and `fieldsets` from the model config.
You have to explicitly define these on your admin
Adds a few mixins over `SimpleKaosModelAdmin` that are used broadly and can be all provided through this class.
Example:
>>> # Make sure `MyModel` has `.config = MyModelConfig()`
>>> @admin.register(MyModel)
>>> class MyModelAdmin(KaosModelAdmin):
>>> # You don't need to define any fields besides fieldsets.
>>> fieldsets = MyModel.config.fieldsets
>>> search_fields = MyModel.config.search_fields # Sometimes you might need to define a field
>>> # explicitly so django doesn't complain. For example search_fields needs to be explicitly set if you are
>>> # using this model in an autocomplete_fields somewhere.
"""
def get_change_actions(self, request, object_id, form_url, obj=None):
obj = self._get_change_action_object(object_id)
change_actions = self.model.config.get_change_actions(request, obj)
return ObjectActionsPermissionsMixin.get_change_actions(self, request, object_id, change_actions, obj)
def get_edit_readonly_fields(self, request, obj=None):
if self.edit_readonly_fields != EditReadonlyAdminMixin.edit_readonly_fields:
return super().get_edit_readonly_fields(request, obj)
return self.model.config.get_edit_readonly_fields(request, obj)
def get_list_filter_autocomplete(self, request):
if self.list_filter_autocomplete != AutocompleteListFilterAdminMixin.list_filter_autocomplete:
return super().get_list_filter_autocomplete(request)
return self.model.config.get_list_filter_autocomplete(request)
__all__ = (
'BaseKaosModelAdmin',
'SimpleKaosModelAdmin',
'ObjectActionsPermissionsMixin',
'KaosModelAdmin',
)