Custom Manager not being implemented for custom User

I have this custom User and Manager implementation subclassing AbstractBaseUser and BaseUserManager in django

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


class AccountManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        values = [email]
        field_value_map = dict(zip(self.model.REQUIRED_FIELDS, values))
        for field_name, value in field_value_map.items():
            if not value:
                raise ValueError("The {} value must be set".format(field_name))

        email = self.normalize_email(email)
        extra_fields.setdefault("username", email)  # this line of code here
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", False)
        extra_fields.setdefault("is_superuser", False)
        extra_fields.setdefault("username", email)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)

        if extra_fields.get("is_staff") is not True:
            raise ValueError("Superuser must have is_staff=True.")
        if extra_fields.get("is_superuser") is not True:
            raise ValueError("Superuser must have is_superuser=True.")

        return self._create_user(email, password, **extra_fields)


class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_("email address"), unique=True)
    username = models.CharField(unique=True, max_length=200)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(default=timezone.now)
    is_superuser = models.BooleanField(default=False)
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)
    address = models.CharField(
        max_length=200,
    )
    latitude = models.FloatField(default=0.00, blank=True)
    longitude = models.FloatField(default=0.00, blank=True)
    dob = models.DateTimeField(null=True, blank=True, default=timezone.now)
    phone = models.CharField(max_length=200, blank=True)
    phone_activated = models.BooleanField(default=False)
    phone_activation_code = models.CharField(max_length=200)
    genderChoices = [("Male", "Male"), ("Female", "Female"), ("Other", "Other")]
    gender = models.CharField(max_length=200, choices=genderChoices, default="Male")
    profile_image = models.ImageField(blank=True)
    cover_photo = models.ImageField(blank=True)
    facebook_link = models.CharField(max_length=200, blank=True)
    twitter_link = models.CharField(max_length=200, blank=True)
    instagram_link = models.CharField(max_length=200, blank=True)
    youtube_link = models.CharField(max_length=200, blank=True)
    linkedin_link = models.CharField(max_length=200, blank=True)
    sendEmail = models.BooleanField(default=True)
    sendSMS = models.BooleanField(default=True)
    activation = models.CharField(max_length=200)

    objects = AccountManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    def __str__(self):
        return self.email

I want to have a username field that could be later edited to a custom one, but at the time of creation equals to the email registered with.

Now when I create a superuser from cli all things go fine and I get what I want. But when I create a user with the django admin, the AccountManager class seem like non existent and none of the code here is implemented. i.e username field is stored as empty the first time and gives a non-unique integrity error the other time(of course). Why is the create_user method not called while creating user from django admin. Can someone help me with this??

The reason that the createsuperuser cli command works is because it specifically calls the create_superuser method on the UserModel.

This is the line from createsuperuser.py:
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)

However, the Admin facility is designed to be generic, and work with every model. It’s not going to perform actions outside what it can expect to have implemented for every model.

When you look at the docs for managers in the section for adding extra manager methods, it reads in part:

Adding extra Manager methods is the preferred way to add “table-level” functionality to your models. (For “row-level” functionality – i.e., functions that act on a single instance of a model object – use Model methods, not custom Manager methods.)

Since what you’re doing here is a row-level action, a manager method doesn’t apply. To do what you’re trying to do, you may want to override the save method on the model.

Ken

1 Like

Oh that was it. Thank you very much. :slight_smile:
Kush