I’m trying to overwrite the built in user creation page of the admin interface to make the group mandatory. This is how I adjusted the UserAdmin class:
# admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth import get_user_model
from .forms import CustomUserChangeForm, CustomUserCreationForm
User = get_user_model()
class CustomUserAdmin(UserAdmin):
form = CustomUserChangeForm
add_form = CustomUserCreationForm
fieldsets = (
(None, {'fields': ('username', 'email', 'password', 'groups')}),
)
add_fieldsets = (
(None, {'fields': ('username', 'email', 'password1', 'password2',
'groups')}),
)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
I tried different approaches as form to mimic the existing field but couldn’t replicate it. I also tried to look at the source code how the original definition for the original group field definition but couldn’t find it.
Keep in mind that the User < - > Group relationship is a many-to-many relationship between those two models. This means that there is no group field in User. The name group is a reference to a related object manager
What that means in this context is that in order to enforce some kind of group relationship, you’ll need to write some type of validation code to check to ensure that a group has been assigned. (I think you could add a clean method to the form to check to ensure that at least one group has been selected.)
Yeah I was able to write a clean method that does the validation but it will display the error at the top of the page and not next to the field like for the other required fields. It’s okay but kinda not what I want. It would also be fine if the admins could only assign one initial group so the following form kinda:
class CustomUserCreationForm(UserCreationForm):
groups = ModelChoiceField(
queryset=Group.objects.all(),
required=True,
widget=forms.Select,
label="Group",
)
def clean(self):
cleaned_data = super().clean()
cleaned_data['groups'] = [cleaned_data.get('groups')]
return cleaned_data
this gives me more or less what I want in terms of the required field and what the admin should be able to select. What I don’t understand with that solution is why there is no automatic “Add new group” button like with the built-in field. My understanding was that Django adds this automatically for ForeignKey fields and I thought the group is one of these.
You can define it as a clean_xxx method on the field. As an input field, it’s not dependent upon other fields, so it can be a field-level clean and not a form-level clean.
Because what you’re creating here is a normal form field and not a field that is being created as a “ModelForm” field. You’re creating a field for the form yourself instead of allowing Django to create it. (Django doesn’t “know” that this new field is actually a reference to the model’s “groups” field.)
What I think you want to do here is just assign the widget to be used for that field in the form, possibly along with a custom clean_groups method. (There may be other changes necessary due to the differences between a foreign key and a many-to-many relationship.)
The groups field is not a Foreign Key, it’s an instance of a related field manager. There is no actual field named groups in the User model. Physically and functionally, there are many differences between a foreign key and a many-to-many relationship.