From 2c76bea1e6291743edec39e55cfdf70518cad93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Mon, 16 Oct 2017 13:17:02 +0200 Subject: [PATCH] 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. --- kfet/auth/fields.py | 58 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/kfet/auth/fields.py b/kfet/auth/fields.py index 6d8d1440..998749f5 100644 --- a/kfet/auth/fields.py +++ b/kfet/auth/fields.py @@ -1,7 +1,21 @@ +import re +from itertools import groupby +from operator import attrgetter + from django import forms +from django.utils.translation import ugettext_lazy as _ 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): def __init__(self, **kwargs): @@ -12,11 +26,49 @@ class GroupsField(forms.ModelMultipleChoiceField): class BasePermissionsField(forms.ModelMultipleChoiceField): def __init__(self, **kwargs): - kwargs.setdefault('widget', forms.CheckboxSelectMultiple) + kwargs.setdefault('widget', forms.CheckboxSelectMultiple(attrs={ + 'field_class': 'permissions-field', + })) super().__init__(**kwargs) - def label_from_instance(self, obj): - return obj.name + # Contain permissions grouped by `ContentType`. Used as choices for + # 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({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):