1

I defined a custom user model in my Django project, which defines the 'email' as the unique identifier. I created a custom user creation form following the Django documentation and registered it in my admin.py. When I start the web server, no errors are shown in the console.

My problem is, that the add_form on the admin page does not show the 'email' field, but only 'username', 'password1' and 'password2'

I read several how to's and tutorials and checked the Django documentation to resolve this issue and am afraid I am missing something.

settings.py

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users.apps.UsersConfig'
]

AUTH_USER_MODEL = 'users.NewUser'

model.py

# Custom User Account Model

from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager


class CustomAccountManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifiers for authentication instead of usernames.
    """
    def create_user(self, email, username, first_name, last_name, password=None, **other_fields):
        if not last_name:
            raise ValueError(_('Users must have a last name'))
        elif not first_name:
            raise ValueError(_('Users must have a first name'))
        elif not username:
            raise ValueError(_('Users must have a username'))
        elif not email:
            raise ValueError(_('Users must provide an email address'))

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

        return user

    def create_superuser(self, email, username, first_name, last_name, password=None, **other_fields):
        """
        Create and save a SuperUser with the given email and password.
        """

        other_fields.setdefault('is_staff', True)
        other_fields.setdefault('is_superuser', True)
        other_fields.setdefault('is_admin', True)

        user = self.create_user(
            email=self.normalize_email(email),
            username=username,
            first_name=first_name,
            last_name=last_name,
            password=password,
            **other_fields
        )

        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.')

        user.save(using=self._db)

        return user


class NewUser(AbstractBaseUser, PermissionsMixin):
    # basic information
    email = models.EmailField(_('email address'), unique=True)
    username = models.CharField(max_length=150, unique=True)
    first_name = models.CharField(max_length=150, blank=True)
    last_name = models.CharField(max_length=150, blank=True)

    # Registration Date
    date_joined = models.DateTimeField(default=timezone.now)  ## todo: unterschied zu 'auto_now_add=True'

    # Permissions
    is_admin = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    objects = CustomAccountManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'first_name', 'last_name']  # Note: USERNAME_FIELD not to be included in this list!

    def __str__(self):
        return self.email

    # For checking permissions. to keep it simple all admin have ALL permissons
    def has_perm(self, perm, obj=None):
        return self.is_admin

    # Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)
    def has_module_perms(self, app_label):
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

forms.py

from django import forms
from django.contrib import admin
from django.core.exceptions import ValidationError

# Import custom user model
from django.contrib.auth import get_user_model
custom_user_model = get_user_model()


class CustomUserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""

    username = forms.CharField(label='Username', min_length=4, max_length=150)
    email = forms.EmailField(label='E-Mail')
    first_name = forms.CharField(label='First Name')
    last_name = forms.CharField(label='Last Name')

    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = custom_user_model
        fields = ('username', 'first_name', 'last_name')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()

        return user

admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin  # Helper Class for creating user admin pages

from .forms import CustomUserCreationForm  #, CustomUserChangeForm
from .models import NewUser, UserProfile


class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm

    model = NewUser

    list_display = ('email', 'username', 'date_joined', 'last_login', 'is_admin', 'is_staff')
    search_fields = ('email', 'username',)
    readonly_fields = ('date_joined', 'last_login',)

    filter_horizontal = ()
    list_filter = ()
    fieldsets = ()


admin.site.register(custom_user_model, CustomUserAdmin)

1 Answer 1

6

Add this code to CustomeUserAdmin:

class CustomUserAdmin(UserAdmin):
    .
    .
    .
    add_fieldsets = UserAdmin.add_fieldsets + (
        (None, {'fields': ('custom_field',)}),
    )

It looks like that form on django admin page is created base on add_fieldsets. I also don't know what add_form does actually.

For more information read django docs: django docs about admin, A full example for Custome users in django admin

If you are using a custom ModelAdmin which is a subclass of django.contrib.auth.admin.UserAdmin, then you need to add your custom fields to fieldsets (for fields to be used in editing users) and to add_fieldsets (for fields to be used when creating a user).

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the hint @MatiYo.. This resolved my problem.. To get the result, which I expected, I added following line: add_fieldsets = ( (None, {'fields': ('custom_field',)}), ) the code example from the Django docs made username & password field appear first and the other fields below them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.