Django: Add user to group via Django Admin

You have to write code to achieve what you want, since django admin provides the change form, for the model that has the M2M field in it, namely User, since m2m to Group is inside that model.

So basically, doing it completely in django admin and nice, you probably need to override several functions and provide your own implementation.

class GroupForm(forms.Form):
    blah
    users = forms.ModelMultipleChoiceField(
        label=_('Users'), required=False, queryset=User.objects.all(),
        widget=FilteredSelectMultiple(is_stacked=True, verbose_name=_('Users')),help_text=mark_safe("Help text")
    )

class GroupAdmin(BaseAdmin):
    form = GroupForm
    # you can here define fieldsets to render your form more beautifully

    def save_related(self, request, form, formsets, change):
        current_group = form.instance
        # ....
        # Update relations between users and the group here, both are
        # accessible with the form instance

    def get_changeform_initial_data(self, request):
        # If you want to render the form with initial data for the user
        # you may optionally override this method as well.
        initial = super(GroupAdmin, self).get_changeform_initial_data(request)
        initial.update({'users': ...})
        return initial

This is the most django-ic way I find to implement what you want! Hope it helps or give you an idea


You need to write some code. Note that the Django admin site is normal Django views and forms!

First create a ModelForm:

from django import forms
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.admin.widgets import FilteredSelectMultiple    
from django.contrib.auth.models import Group


User = get_user_model()


# Create ModelForm based on the Group model.
class GroupAdminForm(forms.ModelForm):
    class Meta:
        model = Group
        exclude = []

    # Add the users field.
    users = forms.ModelMultipleChoiceField(
         queryset=User.objects.all(), 
         required=False,
         # Use the pretty 'filter_horizontal widget'.
         widget=FilteredSelectMultiple('users', False)
    )

    def __init__(self, *args, **kwargs):
        # Do the normal form initialisation.
        super(GroupAdminForm, self).__init__(*args, **kwargs)
        # If it is an existing group (saved objects have a pk).
        if self.instance.pk:
            # Populate the users field with the current Group users.
            self.fields['users'].initial = self.instance.user_set.all()

    def save_m2m(self):
        # Add the users to the Group.
        self.instance.user_set.set(self.cleaned_data['users'])

    def save(self, *args, **kwargs):
        # Default save
        instance = super(GroupAdminForm, self).save()
        # Save many-to-many data
        self.save_m2m()
        return instance

We added a custom Group ModelForm. The second step is to unregister the original Group admin and register a new Group admin that displays our ModelForm:

# Unregister the original Group admin.
admin.site.unregister(Group)

# Create a new Group admin.
class GroupAdmin(admin.ModelAdmin):
    # Use our custom form.
    form = GroupAdminForm
    # Filter permissions horizontal as well.
    filter_horizontal = ['permissions']

# Register the new Group ModelAdmin.
admin.site.register(Group, GroupAdmin)

Screenshot Django custom form and filter_horizontal in Group admin