3

I deleted username field because I wanted user to be able to login with their email address, so I have this in my models.py :

class CustomUser(AbstractUser):
    USER_TYPE = ((1, 'HOD'), (2, 'Staff'), (3, 'Student'))
    username = None
    email = models.EmailField(unique=True)
    user_type = models.CharField(default=1, choices=USER_TYPE, max_length=1)
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []


class Student(models.Model):
    admin = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    gender = models.CharField(max_length=1, choices=GENDER)
    address = models.TextField()
    profile_pic = models.ImageField(upload_to='media')
    session_start_year = models.DateField(null=True)
    session_end_year = models.DateField(null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)

In my views.py, I tried :

user = CustomUser.objects.create_user(email=email, password=password, user_type=3, first_name=first_name, last_name=last_name)

But I got create_user() missing 1 required positional argument: 'username' How can I fix this?

  • `create_user()` requires the first argument to be the username. You are not passing this argument. – John Gordon Sep 30 '20 at 21:10
  • I deleted `username` from my model. I tried passing `username=None` but it says `The given username must be set`. How do I bypass this ? I do not want to keep `username` field at all. Email is okay for me. – Owonubi Job Sunday Sep 30 '20 at 21:13

1 Answers1

5

You need to write a manager for a custom user model [Django-doc] to reimplement the create_user method.

You can thus implement a CustomUserManager:

from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import UserManager

class CustomUserManager(UserManager):

    def _create_user(self, email, password, **extra_fields):
        email = self.normalize_email(email)
        user = CustomUser(email=email, **extra_fields)
        user.password = make_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)
        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)

        assert extra_fields['is_staff']
        assert extra_fields['is_superuser']
        return self._create_user(email, password, **extra_fields)

class CustomUser(AbstractUser):
    # …

    objects = CustomUserManager()

and then you register this manager thus as the objects manager.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • I just tried this but I got `name 'make_password' is not defined`. How do I fix this ? – Owonubi Job Sunday Sep 30 '20 at 21:17
  • @OwonubiJobSunday: you import it `from django.contrib.auth.hashers import make_password` – Willem Van Onsem Sep 30 '20 at 21:19
  • Can you explain what it is that we do here that make the username field optional, compared to how it is in the default mode, when username is required? – Alexander Jun 22 '21 at 08:28
  • Hi @WillemVanOnsem ! I'm trying to use code like you, but it appear the error : `TypeError: BaseManager.all() missing 1 required positional argument: 'self'` – Kev Jun 27 '22 at 08:13
  • 1
    @HuyNguyen: how are you using the manager...? Are you sure you added parenthesis at the end of `objects = CustomUserManager()`? – Willem Van Onsem Jun 27 '22 at 15:33