Django built-in User model source code analysis and custom User code

1. Preface

DjangoProvides us with a built-in Usermodel, no need for us to define additional user models and establish a user system. Its full path is in django.contrib.auth.models.User.

2. User model source code analysis

class User(AbstractUser):
    """
    The user in the Django authentication system is represented by this model

    A username and password are required. The other fields are optional.
    """
    class Meta(AbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'

We can see that Userthis class itself does not do anything, but inherits from the AbstractUserclass, then we check AbstractUserthe source codePython

class  AbstractUser ( AbstractBaseUser, PermissionsMixin ):
    """
    An abstract base class implements a fully functional user model that meets the administrator's authority.

    A username and password are required. The other fields are optional.
    """
    # User verification
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=150, blank=True)
    email = models.EmailField(_('email address'), blank=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
    
    # objects user management, there are methods to create users
    objects = UserManager()

    EMAIL_FIELD = 'email'
    # A string used to describe the name field of the User model as a unique identifier. If there is no modification, USERNAME will be used as the only field.
    USERNAME_FIELD = 'username'
    # A list of field names, used for prompts when creating a user through the createsuperuser management command.
    REQUIRED_FIELDS = ['email']

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
        abstract = True

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def get_full_name(self):
        """
        Return first_name and last_name with a space in between
        """
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        """Return the user's first_name."""
        return self.first_name

    def email_user(self, subject, message, from_email=None, **kwargs):
        """Send an email to the user."""
        send_mail(subject, message, from_email, [self.email], **kwargs)

We can see AbstractUserinherited from AbstractBaseUserandPermissionsMixin

  • AbstractBaseUser: Basic User model class
  • PermissionsMixin: Permission class

Let’s take AbstractUsera look at the fields and methods

2.1 Field

  1. username:username. Within 150 characters. It may contain numbers and English characters, as well as _@+.and -character. Cannot be empty, and must be unique!
  2. first_name: For foreigners first_name, within 30 characters. Can be empty.
  3. last_name: For foreigners last_name, within 150 characters. Can be empty.
  4. email:mailbox. Can be empty.
  5. password:password. The hashed password. ( AbstractBaseUserProperties of the parent class )
  6. groups: Grouping. A user can belong to multiple groups, and a group can have multiple users. groupsThis field is Groupa many-to-many relationship with. ( PermissionsMixinProperties of the parent class )
  7. user_permissions: Permission. A user can have multiple permissions, and a permission can be used by multiple users. And Permissionbelongs to a many-to-many relationship. ( PermissionsMixinProperties of the parent class )
  8. is_staff: Whether you can enter adminthe site. Whether the representative is an employee
  9. is_active: Whether it is available. For some data that wants to delete the account, we can set this value Falseinstead of actually deleting it from the database.
  10. is_superuser: Whether it is a super administrator. If you are a super administrator, you have all permissions for the entire website. ( PermissionsMixinProperties of the parent class )
  11. last_login: Last login time. ( AbstractBaseUserProperties of the parent class )
  12. date_joined: The time when the account was created.

3. Basic usage of User model

3.1 Create user

To create a user need to use objects = UserManager()the method, we click to UserManagerview the source codePython

 UserManager class ( BaseUserManager ):
    use_in_migrations = True

    def _create_user(self, username, email, password, **extra_fields):
        """
        Create and save users with the given username, email and password.
        """
        # If there is no username, an exception is thrown
        if not username:
            raise ValueError('The given username must be set')
        # Standardize email, check the source code, you will find that it is split with @
        email = self.normalize_email(email)
        # Standardized username
        username = self.model.normalize_username(username)
        user = self.model(username=username, email=email, **extra_fields)
        # Set a password for the user, convert the plain text password into a hash value for database storage
        user.set_password(password)
        # Save user
        user.save(using=self._db)
        return user

    def create_user(self, username, email=None, password=None, **extra_fields):
        # Set the default value of is_staff to False, and the default value of is_superuser to False
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(username, email, password, **extra_fields)

    def create_superuser(self, username, email, password, **extra_fields):
        # Set the default value of is_staff to True, and the default value of is_superuser to True
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        
        # If you call this method, is_staff must be True, otherwise an exception will be thrown
        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        # If you call this method, is_superuser must be True, otherwise an exception will be thrown
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

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

The above source code is written very clearly. I believe that the friends can see it very clearly. Let’s take a look at the actual operation.CSS

def index(request):
    user = User.objects.create_user(username="jkc", email="[email protected]", password="123456")
    user. save ()
    return HttpResponse("ok")

After we visited the above view, we created an ordinary user to view the auth_usertable in the database , as follows

3.2 Create super user

There are two ways to create a super user. The first is the way to use code. Creating a super user with code is very similar to creating a normal user, except for use create_superuser. The sample code is as follows:CSS

def index(request):
    user = User.objects.create_superuser(username="jkc3", email="[email protected]", password="123456")
    user. save ()
    return HttpResponse("ok")

You can also use the command line. The command is as follows:

python manage.py createsuperuser

You will be prompted to enter your username, email and password later.

3.3 change Password

Because the password needs to be encrypted before it can be stored. Therefore, if you want to modify the password, you cannot modify the passwordfield directly , but need to call set_passwordto achieve the purpose of modifying the password. The sample code is as follows:CSS

def index(request):
    user = User.objects.get(pk=1)
    user.set_password('111111')
    user. save ()
    return HttpResponse("ok")

What is the password before the $1FMDwi2zsgQu$2+8/zL6ZR43oXIvIRGfK6xrWUnv2IRjdPxVaqEwqyjM=change, and after the change is$u6rNdNTvLbEG$r4TcrVsTsibcVF3ZfZIJPjLNvq73wyusLShDmpSZeKM=
 

3.4 Login authentication

DjangoThe verification system of has helped us realize the function of login verification. It django.contrib.auth.authenticatecan be achieved through . This method can only be verified by usernamesum password. The sample code is as follows:Python

def index(request):
    user = authenticate(username="jkc", password="111111")
    if user:
        return HttpResponse( "Login successful" )
    else:
        return HttpResponse( "Login failed" )

4. Extended user model

Django’s built-in User model is powerful enough though. But sometimes it still doesn’t meet our needs. For example, when verifying user login, he uses username as verification, while we sometimes need to verify by mobile number or email. And for example, we want to add some new fields. Then we need to extend the user model. There are various ways to extend the user model. Let’s discuss them in detail here.

4.1 Inherited from AbstractUser

If you are not satisfied with authenticate and do not want to modify some fields on the original User object, but want to add some fields, then you can inherit directly from django.contrib.auth.models.AbstractUser, which is actually the parent class of django.contrib.auth. models.User’s parent class. For example, we want to add a phone field on top of the original User model. The sample code is as follows.

from django.contrib.auth.base_user import BaseUserManager
from django.db import models
from django.contrib.auth.models import AbstractUser


 UserManager class ( BaseUserManager ):
    use_in_migrations = True

    def _create_user(self,phone,password,**extra_fields):
        if not phone:
            raise ValueError( "Please fill in your mobile phone number!" )
        if not password:
            raise ValueError( 'Please enter the password!' )
        user = self.model(phone=phone,*extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_user(self,phone,password,**extra_fields):
        extra_fields.setdefault('is_superuser',False)
        return self._create_user(phone,password)

    def create_superuser(self,phone,password,**extra_fields):
        extra_fields['is_superuser'] = True
        return self._create_user(phone,password)


class User(AbstractUser):
    phone = models.CharField(max_length= 11 , unique= True , verbose_name= "phone number" )
    # Specify phone as USERNAME_FIELD, use authenticate in the future
    # When the function is verified, it can be verified by phone instead of the original username
    USERNAME_FIELD = 'phone'
    # Remind the user to enter the field
    REQUIRED_FIELDS = []

    # Redefine the Manager object, use phone and password when creating a user, instead of using username and password
    objects = UserManager()

Then configure AUTH_USER_MODEL=yourapp.User in settings again.
Note: This way, because it breaks the table structure of the original User model, it must be defined before the first migrate.
Above we redefine the User model, add the phone field, and use phone as the check field, let’s look at the database table structure first.

Next, we create a superuser by using the createesuperuser command.

We will find that when we create the superuser, we no longer need the username field to verify it, next we verify the login, the structure now requires the phone field and password to login instead of using username, we write the view function to try it.

def index(request):
    # First log in with your mobile phone number and password
    user = authenticate(username="12345678901", password="admin123")
    if user:
        return HttpResponse( 'Mobile phone number password login successfully' )
    else:
        return HttpResponse( 'Mobile phone number password login failed' )

Then visit the view and return the cell phone number password login success, indicating that the content of the field of the verification is now the cell phone number, let’s try again to use the user name can login successfully.

def index(request):
    # Since ?username has not been set before, here first set the username for the user whose ?id is 1
    user = User.objects.get(pk=1)
    user.username = "jkc"
    user.save()
    print ( "Saved successfully" )
    u = authenticate(username="jkc", password="admin123")
    if u:
        return HttpResponse( 'Username login successfully' )
    else:
        return HttpResponse( 'Username login failed' )

We visit the view, the last return is the cell phone number verification code login failure, indicating that now username verification is cell phone number, we enter the user name is verification failed.

Original address https://www.cnblogs.com/jiakecong/p/14875555.html

Leave a Reply