Better display of objects of BasePermissionsField

- Permissions are grouped by content type and displayed under its
verbose_name_plural.
- Default permissions appear before custom ones.
- Use `permissions-field` class to enhance display.
This commit is contained in:
Aurélien Delobelle 2017-10-16 13:17:02 +02:00
parent 07f1a53532
commit 2c76bea1e6

View file

@ -1,7 +1,21 @@
import re
from itertools import groupby
from operator import attrgetter
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _
from .models import Group, Permission from .models import Group, Permission
DEFAULT_PERMS = ['view', 'add', 'change', 'delete']
DEFAULT_PERMS_LABELS = {
'view': _("Voir"),
'add': _("Ajouter"),
'change': _("Modifier"),
'delete': _("Supprimer"),
}
class GroupsField(forms.ModelMultipleChoiceField): class GroupsField(forms.ModelMultipleChoiceField):
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -12,11 +26,49 @@ class GroupsField(forms.ModelMultipleChoiceField):
class BasePermissionsField(forms.ModelMultipleChoiceField): class BasePermissionsField(forms.ModelMultipleChoiceField):
def __init__(self, **kwargs): def __init__(self, **kwargs):
kwargs.setdefault('widget', forms.CheckboxSelectMultiple) kwargs.setdefault('widget', forms.CheckboxSelectMultiple(attrs={
'field_class': 'permissions-field',
}))
super().__init__(**kwargs) super().__init__(**kwargs)
def label_from_instance(self, obj): # Contain permissions grouped by `ContentType`. Used as choices for
return obj.name # this field.
grouped_choices = []
for ct, perms in groupby(self.queryset, attrgetter('content_type')):
model_opts = ct.model_class()._meta
choices = []
# This helps for the default permissions, if they exists, to appear
# at the beginning of the permissions list and use custom labels.
reg_defaults_p = re.compile(
r'^(?P<p_type>({defaults}))_{model_name}$'
.format(
defaults='|'.join(DEFAULT_PERMS),
model_name=model_opts.model_name,
)
)
next_default_pos = 0
for p in perms:
match = reg_defaults_p.match(p.codename)
if match:
# `p` is a default permission. Use shorter label and insert
# after the last default permission seen in `choices`.
p_type = match.group('p_type')
choices.insert(
next_default_pos,
(p.id, DEFAULT_PERMS_LABELS[p_type])
)
next_default_pos += 1
else:
# Non-default permissions. Use the permission description,
# instead of its `__str__`.
choices.append((p.id, p.name))
grouped_choices.append((model_opts.verbose_name_plural, choices))
self.choices = grouped_choices
class CorePermissionsField(BasePermissionsField): class CorePermissionsField(BasePermissionsField):