pythondjangodjango-formsdjango-admindjango-guardian

How to add group choices in the Object Permissions form of the admin interface with django-guardian?


Using guardian in a django project, I want the admins to be able to assign object permissions over the admin interface. With guardian this is possible, but the Object permissions form in the admin interface, the Group field is a TextField. How do I make it a ChoiceField with all existing groups as choices?

Is there a solution that only requires adding code in the admin.py file of the app or do we have to overwrite some guardian code? How can we do it without messing with the functionality of guardian? This is my admin.py file:

from django.contrib import admin
from .models import MyModel
from guardian.admin import GuardedModelAdmin

class MyModelAdmin(GuardedModelAdmin):
    pass


admin.site.register(MyModel, MyModelAdmin)

Solution

  • Here is the solution that works like a charm. First subclass the GuardedModelAdminMixin

    from guardian.admin import GuardedModelAdmin, GuardedModelAdminMixin
    
    class CustomGuardedModelAdminMixin(GuardedModelAdminMixin):
        def get_obj_perms_group_select_form(self, request):
            """
            Returns form class for selecting a group for permissions management.  By default :form:`GroupManage` is
            returned. This enhancement returns GroupModelManage instead, allowing admins to get a queryset of groups.
            """
            return GroupModelManage
    

    Then define the ModelManager for groups with overriding the clean_group function:

    class GroupModelManage(forms.Form):
        """
        Extends the Django Guardian GroupManage class to select User from a query containing all
        User objects rather than a blank input CharField.
        """
        group = forms.ModelChoiceField(queryset=Group.objects.all())
    
        def clean_group(self):
            """
            Returns ``Group`` instance based on the given group name.
            """
            try:
                return self.cleaned_data['group']
            except Group.DoesNotExist:
                raise forms.ValidationError(self.fields['group'].error_messages['does_not_exist'])
    

    Finally, use the new Mixin in your Admin class:

    class MyModelAdmin(CustomGuardedModelAdminMixin, admin.ModelAdmin):
        pass
    
    admin.site.register(MyModel, MyModelAdmin)
    

    To do custom querysets on the user level, use this function in the new mixin:

        def get_obj_perms_user_select_form(self, request):
            return UserModelManage
    

    A full example is here: LINK