guettli
guettli

Reputation: 27796

Django: Add user to group via Django Admin

How can I add users to a group in Django admin interface of "Change Group"?

I have seen dirty hacks to get this working for older django version.

How to solve this with Django 1.10?

Emphasize: I want this on the page "Change Group", not on "Change User".

I would like to have this in django-admin-style: No coding, just doing some configuration. Maybe like this:

class GroupAdmin(admin.ModelAdmin):
    show_reverse_many_to_many = ('user',)

Upvotes: 15

Views: 16697

Answers (4)

Shivansh Jagga
Shivansh Jagga

Reputation: 1861

The winning answer didn't work for me. It was giving me a conflict while registering the new group class I created. I had to create a proxy Group class instead for it to work.

class CustomGroup(Group):
    class Meta:
        proxy = True

# Define a custom form for the extended Group model
class CustomGroupAdminForm(forms.ModelForm):
    users = forms.ModelMultipleChoiceField(
        queryset=User.objects.all(),
        required=False,
        widget=FilteredSelectMultiple('Users', False)
    )


    class Meta:
        model = CustomGroup
        exclude = []

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance.pk:
            self.fields['users'].initial = self.instance.user_set.all()


    def save(self, commit=True):
        group = super().save(commit=False)
        if not commit:
            group
        group.user_set.set(self.cleaned_data['users'])
        group.permissions.set(self.cleaned_data['permissions'])
        group.save()
        return group

# Customize the Group admin using the default GroupAdmin class
class CustomGroupAdmin(BaseGroupAdmin):
    form = CustomGroupAdminForm
    filter_horizontal = ['permissions']

And then registering it

# Register the CustomGroup model with the custom admin
admin.site.unregister(Group)  # Unregister the default Group admin
admin.site.register(Group, CustomGroupAdmin)  # Register CustomGroup with the custom admin

Upvotes: 1

allcaps
allcaps

Reputation: 11228

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

Upvotes: 60

Alireza
Alireza

Reputation: 4516

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

Upvotes: 2

Dimitris Kougioumtzis
Dimitris Kougioumtzis

Reputation: 2439

On Change group page you have to override the change group form and add a multiple selectbox with users

Upvotes: 0

Related Questions