DJANGO custom user model: create_superuser() missing 1 required positional argument: 'username'

Question:

I have the following User model which uses email as USERNAME_FIELD and leave the actual username unused.

All authentication features work fine, but I just realized I cannot create superuser with manage.py because of the error: create_superuser() missing 1 required positional argument: 'username'

Can anyone help me debug this error?

users/models.py

class User(AbstractUser):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    username = None
    first_name = models.CharField(max_length=100, default="unknown")
    last_name = models.CharField(max_length=100, default="unknown")
    profile_pic = models.CharField(max_length=200, default="unknown")
    premium = models.BooleanField(default=False)

    email = models.EmailField(unique=True, db_index=True)
    secret_key = models.CharField(max_length=255, default=get_random_secret_key)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    class Meta:
        swappable = "AUTH_USER_MODEL"

users/services.py

def user_create(email, password=None, **extra_fields) -> User:
    extra_fields = {"is_staff": False, "is_superuser": False, **extra_fields}

    user = User(email=email, **extra_fields)

    if password:
        user.set_password(password)
    else:
        user.set_unusable_password()

    user.full_clean()
    user.save()

    return user


def user_create_superuser(email, password=None, **extra_fields) -> User:
    extra_fields = {**extra_fields, "is_staff": True, "is_superuser": True}

    user = user_create(email=email, password=password, **extra_fields)

    return user

@transaction.atomic
def user_get_or_create(
    *, email: str, first_name: str, last_name: str, profile_pic: str
) -> Tuple[User, bool]:
    user = User.objects.filter(email=email).first()

    if user:
        return user, False

    return (
        user_create(
            email=email,
            first_name=first_name,
            last_name=last_name,
            profile_pic=profile_pic,
        ),
        True,
    )

Full error log

❯ docker-compose run --rm web ./manage.py createsuperuser                                                                                                                               ─╯
Email: [email protected]
Password: 
Password (again): 
Traceback (most recent call last):
  File "./manage.py", line 30, in <module>
    main()
  File "./manage.py", line 26, in main
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 425, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 419, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 373, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 79, in execute
    return super().execute(*args, **options)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 417, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 195, in handle
    self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
TypeError: create_superuser() missing 1 required positional argument: 'username'
Asked By: Tyler Kim

||

Answers:

create_superuser may not work for the customer User Model. You may implement the BaseUserManager to do that.

class CustomerManager(BaseUserManager):

    def create_superuser(self, email, password):
        # create superuser here
        ...

here is the official document.

Answered By: Allen Shaw

I solved this issue by adding this custom UserManager.
Thank you Allen, Adam, and Ghazi!

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        extra_fields = {"is_staff": False, "is_superuser": False, **extra_fields}
        if not email:
            raise ValueError("Users must have an email address")

        user = User(email=email, **extra_fields)

        if password:
            user.set_password(password)
        else:
            user.set_unusable_password()

        return user

    def create_superuser(self, email, password=None, **extra_fields):

        extra_fields = {**extra_fields, "is_staff": True, "is_superuser": True}

        user = self.create_user(email=email, password=password, **extra_fields)

        return user
Answered By: Tyler Kim