Django Admin Not Being Overridden By Custom

Hi,

I’ve created a custom user and tried adding it to my admin page like this:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from simple_history.admin import SimpleHistoryAdmin

from .models import User, Account


class MyUserAdminConfig(UserAdmin):
    model = User
    search_fields = ('email', 'first_name', 'last_name')
    list_filter = ('is_active', 'is_staff', 'is_superuser')
    ordering = ('-is_staff', '-start_date')
    list_display = ('email', 'first_name', 'last_name',
                    'is_active', 'is_staff', 'is_superuser')
    fieldsets = (
        ('User Info', {'fields': ('email', 'first_name', 'last_name')}),
        ('Permissions', {'fields': ('is_staff', 'is_active', 'is_superuser')}),
    )
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'first_name', 'last_name', 'password', 'is_staff', 'is_active'),
        }),
    )


@admin.register(Account)
class AccountAdmin(SimpleHistoryAdmin):
    list_display = ('id', 'user', 'status')
    list_filter = ('status',)
    raw_id_fields = ('user',)


admin.site.register(User, MyUserAdminConfig)

When I try and create a user through my admin page I see this it gives me an error on the top of the page saying “Please correct the errors below.” But it doesn’t give any errors in the fields. Now when I comment out the add_fieldsets section I can see this:


Which looks like the default user page and is showing me what I’m missing. I don’t understand why this isn’t being overridden by my custom user.

My custom user model looks like this:

class CustomAccountManager(BaseUserManager):
    def create_superuser(self, email, first_name, last_name, password, **other_fields):
        other_fields.setdefault('is_staff', True)
        other_fields.setdefault('is_superuser', True)
        other_fields.setdefault('is_active', True)

        if other_fields.get('is_staff') is not True:
            raise ValueError(
                'Superuser must be assigned to is_staff=True.'
            )
        if other_fields.get('is_superuser') is not True:
            raise ValueError(
                'Superuser must be assigned to is_superuser=True'
            )

        return self.create_user(email, first_name, last_name, password, **other_fields)

    def create_user(self, email, first_name, last_name, password, **other_fields):
        if not email:
            raise ValueError(_('You must provide an email address'))

        email = self.normalize_email(email)
        user = self.model(email=email,
                          first_name=first_name,
                          last_name=last_name,
                          **other_fields,
                          )
        user.username = email
        user.set_password(password)
        user.save()

        return user


class User(AbstractUser):
    """A custom user model for extension"""

    email = models.EmailField(_("email address"), unique=True)
    first_name = models.CharField(max_length=150, blank=True)
    last_name = models.CharField(max_length=150, blank=True)
    start_date = models.DateField(default=timezone.now)
    is_staff = models.BooleanField(default=False)
    objects = CustomAccountManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["first_name", "last_name"]

    def __str__(self):
        return self.email

Anyone faced this issue as well? I can’t seem to find an answer through google so not sure where to go from here. I’m sure I’m missing something obvious…

Edit:
I’ve also created a custom signup form:

class CustomSignupForm(SignupForm):
    first_name = forms.CharField(max_length=30, label='First Name')
    last_name = forms.CharField(max_length=30, label='Last Name')

    def save(self, request):
        user = super(CustomSignupForm, self).save(request)
        user.first_name = self.cleaned_data['first_name'].capitalize()
        user.last_name = self.cleaned_data['last_name'].capitalize()
        user.save()

        return user

    class Meta:
        model = User
        fields = ('email',)

Thanks,
Mitchell

The UserAdmin class is not your typical Django Admin class. There’s a lot more going on there than what might be immediately apparent.

I suggest you read the source for it to understand everything it’s doing before you try to subclass it. Either that, or don’t inherit from it - build your admin class from scratch. If you do that, be careful with handling the password field(s) - you want to ensure that you don’t store plain-text passwords in your database.

I also want to point out that this may not give the desired behavior if not handled on the correct place. Normally this code will be called after validation, and there is no handler for the ValueError / ValidationError exceptions, so that will cause a 500 Internal Server Error instead.

Maybe this validation can go elsewhere?