Repository URL to install this package:
|
Version:
0.2.0a11 ▾
|
from __future__ import annotations
from typing import Sequence
from django.contrib import admin
from django.contrib.admin.options import BaseModelAdmin
from django.contrib.auth import get_user_model
from django_object_actions import BaseDjangoObjectActions
class AreYouSureActionsAdminMixin(BaseDjangoObjectActions):
"""
Add a confirmation prompt to the certain object actions defined in :attr:`are_you_sure_actions`.
:param are_you_sure_actions: sequence of object actions that require confirmation upon clicking.
:param are_you_sure_prompt_f: the template of the message shown in the confirmation prompt.
Example:
>>> class MyModelAdmin(AreYouSureActionsAdminMixin, admin.ModelAdmin):
>>> are_you_sure_actions = ('archive',)
"""
are_you_sure_actions = ()
are_you_sure_prompt_f = "Are you sure you want to {label} this object?"
def __init__(self, *args, **kwargs):
super(AreYouSureActionsAdminMixin, self).__init__(*args, **kwargs)
for action in self.are_you_sure_actions:
tool = getattr(self, action)
label = getattr(tool, 'label', action).lower()
are_you_sure_prompt = self.are_you_sure_prompt_f.format(tool=tool, label=label)
tool.__dict__.setdefault('attrs', {})
tool.__dict__['attrs'].setdefault('onclick', f"""return confirm("{are_you_sure_prompt}");""")
class ExcludeFromNonSuperusersMixin(BaseModelAdmin):
"""
Admin mixin to make some fields hidden to non-superusers. Define such fields using
:attr:`.exclude_from_non_superusers`, or dynamically by overriding :attr:`.get_exclude_from_non_superusers()`.
:param exclude_from_non_superusers: sequence of field names that are not shown to non-superusers
Example:
>>> class MyModelAdmin(ExcludeFromNonSuperusersMixin, admin.ModelAdmin):
>>> exclude_from_non_superusers = ('is_superuser',)
"""
exclude_from_non_superusers = ()
def get_exclude_from_non_superusers(self, request, obj=None):
"""
Return a sequence of field names that are not shown to non-superusers.
By default, return `self.exclude_from_non_superusers`.
"""
return self.exclude_from_non_superusers
def get_exclude(self, request, obj=None):
exclude = super(ExcludeFromNonSuperusersMixin, self).get_exclude(request, obj) or ()
if request.user.is_superuser:
return exclude
return (
*exclude,
*self.get_exclude_from_non_superusers(request, obj),
)
class FilterOutSuperusersAdminMixin(BaseModelAdmin):
"""
A mixin for filtering out superusers from the foreign key and many-to-many fields in the admin interface.
:param user_fields: List of field names with fk or m2m to User.
"""
user_fields: Sequence[str] = ()
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if not request.user.is_superuser and db_field.name in self.user_fields:
kwargs['queryset'] = get_user_model().objects.filter(is_superuser=False)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
def formfield_for_manytomany(self, db_field, request, **kwargs):
if not request.user.is_superuser and db_field.name in self.user_fields:
kwargs['queryset'] = get_user_model().objects.filter(is_superuser=False)
return super().formfield_for_manytomany(db_field, request, **kwargs)
class AutoUserAdminMixin(BaseModelAdmin):
"""
Mixin to automatically set the owner field to the current user as the initial value of the form.
:param user_field: The name of the field with the foreign key to user
"""
user_field = 'user'
def formfield_for_foreignkey(self, db_field, request, **kwargs):
field = super().formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == self.user_field and field.initial is None:
field.initial = request.user
return field
class EditReadonlyAdminMixin(BaseModelAdmin):
"""
Fields defined in :attr:`edit_readonly_fields` are editable upon creation, but are readonly on an existing object.
Set :attr:`allow_superusers` to True to allow superusers to edit such fields even in existing objects.
:param edit_readonly_fields: sequence of field names that can be entered during creation, but are readonly on an
existing object.
:param allow_superusers: Whether to allow superusers to edit `edit_readonly_fields` even on existing object. False
by default.
Example:
>>> class MyModelAdmin(EditReadonlyAdminMixin, admin.ModelAdmin):
>>> edit_readonly_fields = ('slug',)
"""
edit_readonly_fields = ()
allow_superusers = False
def get_edit_readonly_fields(self, request, obj=None):
return self.edit_readonly_fields
def get_readonly_fields(self, request, obj=None):
readonly_fields = super().get_readonly_fields(request, obj)
if not obj: # is in add form not edit
return readonly_fields
if self.allow_superusers and request.user.is_superuser:
return readonly_fields
return readonly_fields + self.get_edit_readonly_fields(request, obj)
class ExcludeFromFieldsetsMixin(BaseModelAdmin):
"""
Admin mixin to make sure fields that are in :attr:`exclude` are removed from the :attr:`fieldsets` definition.
By default, without this mixin, if a field defined in :attr:`fieldsets` is in :attr:`exclude`, Django throws an
error complaining about a missing value for the field.
Example:
>>> class MyModelAdmin(ExcludeFromFieldsetsMixin, admin.ModelAdmin):
>>> pass
"""
def get_fieldsets(self, request, obj=None):
exclude = self.get_exclude(request, obj)
fieldsets = super().get_fieldsets(request, obj) or ()
if not exclude:
return fieldsets
return [
(fieldset_name,
{
**fieldset_dict,
'fields': [field for field in fieldset_dict['fields'] if field not in exclude]
})
for fieldset_name, fieldset_dict in fieldsets
]
__all__ = (
'AreYouSureActionsAdminMixin',
'ExcludeFromNonSuperusersMixin',
'FilterOutSuperusersAdminMixin',
'AutoUserAdminMixin',
'EditReadonlyAdminMixin',
'ExcludeFromFieldsetsMixin',
)