I don't understand how creating a custom user works

I’m reading the Django 3.2 documentation (custom authentication) and there are some lines of code that I can’t understand.

I will try to read and explain what I can understand, or what I think I understand. Please correct me if I am wrong

Resource link: Customizing authentication in Django | Documentación de Django | Django

from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)


class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, date_of_birth, password=None):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        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

T his method is used to create a standard user, it receives 2 main parameters: email and password.

def create_user(self, email, password=None):
    if not email:
        raise ValueError("Users must have an email address")

    user = self.model(
        email=self.normalize_email(email),
    )

    user.set_password(password)
    user.save(using=self._db)
    return user

If the field is not of the email type, execute error
(am I wrong)?:

if not email:
    raise ValueError("Users must have an email address")

I dont understand; I know that the normalize_email method puts all text in lowercase. But I don’t understand the self.model (): this is not a method, is it? Shouldn’t it be like this: user.email = self.normalize_email (email)?

user = self.model(
    email=self.normalize_email(email),
)

The set_password method takes as an argument ‘password’ that the user entered, encrypts it and stores it in a structure or instance called user.

user.set_password(password)

The “save” method stores the record we have entered in the database. I have no idea how using = self._db works. Wouldn’t it be enough to just call the save method? example user.save()

user.save(using=self._db)

create_superuser This method creates an Admin, receives an email and a password. But I don’t understand why you are referring to the create_user method.

user = self.create_user(...)

There is a line of code in the model that I don’t understand its functionality either. Why instantiate the MyUserManager class in a variable called objects?

objects = MyUserManager()

Please explain me in an easy way

What you’re looking at here is a ModelManager, not the model itself.

If you dig through the source to see what all is going on here, you’ll see that the model attribute within the ModelManager is set to the model class to which it applies.

So, let’s say that you have a class named MyClass. You can create an instance of MyClass like this:
my_class = MyClass(field1=value1, field2=value2, field3=value3)

In this case, if we set:
self.model = MyClass
then we can say:
my_class = self.model(field1=value1, field2=value2, field3=value3)

So that’s what’s happening here. The model attribute of the ModelManager class is an alias for the Model class, and you’re creating an instance of that model.