Reputation: 27796
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
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
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)
Upvotes: 60
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
Reputation: 2439
On Change group page you have to override the change group form and add a multiple selectbox with users
Upvotes: 0