robertkovac / django-fieldsets-with-inlines

Mixin inlines and fieldsets in Django admin
Other
16 stars 10 forks source link

When using fieldsets_with_inlines breaks django add user #2

Open ezmodus opened 4 years ago

ezmodus commented 4 years ago

Using Django 3.1 and Python 3.8.5 if this fieldsets_with_inlines are used to order UserAdmin it will break add user logic, because it loads fieldsets also in this view. Normally when you "add user" in admin it first forces you to fill: username, password1 and password2, after that you can edit user. This needs to be updated that fieldsets can be ignored if using add-feature.

This is default "add user" (sorry it is in Finnish) image

ezmodus commented 4 years ago

Okay I made a hack to overwrite this, but I changed my fieldset_with_inlines in UserAdmin to something else, eg fieldset_template (something what is not reserved by django like fieldsets).

Then I override ModelAdmin get_fieldsets(self, request, obj=None)-function to load different if we ain't working with change instead we are working with add.

# Simplified version of custom UserAdmin what I use in my project
# UserAdmin is from django.contrib.auth.admin

@admin.register(User)
class MyUserAdmin(FieldsetsInlineMixin, UserAdmin):
    add_form = UserCreateForm # my custom form to override some default django auth.User specific data
    list_display = ('email', 'username', 'is_active', 'is_superuser')
    list_filter = ('is_active', 'groups')
    search_fields = ('username', 'first_name', 'last_name', 'email', 'phone')
    readonly_fields = ('last_login',)
    filter_horizontal = ('groups',)
    list_display_links = ('email', 'username')

    def get_fieldsets(self, request, obj=None):
        # this is where magic happens, because default django UserAdmin clears fieldsets when inserting new user
        # add populates from UserAdmin a values from add_fieldsets
        # because fieldsets_with_inlines does not handle these (instead always injects the fieldsets if set)
        # this way I can force fieldsets to be different based on action
        if not obj:
            self.fieldsets_with_inlines = (
                (None, {
                    'classes': ('wide',),
                    'fields': ('username', 'email', 'password1', 'password2'),
                }),
            )
        else:
            self.fieldsets_with_inlines = self.fieldset_template
        return super().get_fieldsets(request, obj)

    fieldset_template = (
        (
            'ACCOUNT', {
                'fields': ('username', 'email', 'password', 'last_login')
            }
        ),
        ProfileInline, # just random inline here
        (
            'PERSONAL INFORMATION', {
                'fields': ('first_name', 'last_name', 'phone')
            }
        ),
        (
            'PERMISSIONS', {
                'fields': ('is_active', 'is_superuser', 'is_staff', 'groups')
            }
        ),
    )