前言

Django为我们提供了内置的User模型,不需要我们再额外定义用户模型,建立用户体系了。它的完整的路径是在django.contrib.auth.models.User

User模型源码分析

class User(AbstractUser):
"""
Django 身份验证系统中的用户由该模型表示 需要用户名和密码。其他字段是可选的。
"""
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'

我们可以看到User这个类本身没干什么事情,而是继承自AbstractUser类,那么我们查看下AbstractUser的源码

class AbstractUser(AbstractBaseUser, PermissionsMixin):
"""
一个抽象基类实现了一个功能齐全的用户模型 符合管理员的权限。 需要用户名和密码。 其他字段是可选的。
"""
# 用户民校验
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用户管理,里面有创建用户的方法
objects = UserManager() EMAIL_FIELD = 'email'
# 用来描述User模型名字字段的字符串,作为唯一的标识。如果没有修改,那么会使用USERNAME来作为唯一字段。
USERNAME_FIELD = 'username'
# 一个字段名列表,用于当通过createsuperuser管理命令创建一个用户时的提示。
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):
"""
返回first_name和last_name,中间有个空格
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip() def get_short_name(self):
"""返回用户的first_name."""
return self.first_name def email_user(self, subject, message, from_email=None, **kwargs):
"""发送邮件给用户."""
send_mail(subject, message, from_email, [self.email], **kwargs)

我们可以看到AbstractUser继承自AbstractBaseUserPermissionsMixin

  • AbstractBaseUser:基础的User模型类
  • PermissionsMixin:权限类

我们先看看AbstractUser有哪些字段和方法

字段

  1. username:用户名。150个字符以内。可以包含数字和英文字符,以及_@+.-字符。不能为空,且必须唯一!
  2. first_name:外国人的first_name,在30个字符以内。可以为空。
  3. last_name:外国人的last_name,在150个字符以内。可以为空。
  4. email:邮箱。可以为空。
  5. password:密码。经过哈希过后的密码。(父类AbstractBaseUser的属性)
  6. groups:分组。一个用户可以属于多个分组,一个分组可以拥有多个用户。groups这个字段是跟Group的一个多对多的关系。(父类PermissionsMixin的属性)
  7. user_permissions:权限。一个用户可以拥有多个权限,一个权限可以被多个用户所有用。和Permission属于一种多对多的关系。(父类PermissionsMixin的属性)
  8. is_staff:是否可以进入到admin的站点。代表是否是员工
  9. is_active:是否是可用的。对于一些想要删除账号的数据,我们设置这个值为False就可以了,而不是真正的从数据库中删除。
  10. is_superuser:是否是超级管理员。如果是超级管理员,那么拥有整个网站的所有权限。(父类PermissionsMixin的属性)
  11. last_login:上次登录的时间。(父类AbstractBaseUser的属性)
  12. date_joined:账号创建的时间。

User模型基本用法

创建用户

创建用户需要用到objects = UserManager()中的方法,我们点击UserManager查看源码

class UserManager(BaseUserManager):
use_in_migrations = True def _create_user(self, username, email, password, **extra_fields):
"""
使用给定的用户名、电子邮件和密码创建并保存用户。
"""
# 如果没有username则抛出异常
if not username:
raise ValueError('The given username must be set')
# 标准化电子邮件,查看源码会发现是用@进行分割
email = self.normalize_email(email)
# 标准化用户名
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
# 为用户设置密码,将纯文本密码转换为用于数据库存储的哈希值
user.set_password(password)
# 保存用户
user.save(using=self._db)
return user def create_user(self, username, email=None, password=None, **extra_fields):
# 设置is_staff默认值为False,is_superuser默认值为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):
# 设置is_staff默认值为True,is_superuser默认值为True
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True) # 如果调用此方法,is_staff必须为True,否则会抛出异常
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
# 如果调用此方法,is_superuser必须为True,否则会抛出异常
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)

以上源码写的十分清楚相信小伙伴们也看得很清晰了,接下里我们实际操作一下

def index(request):
user = User.objects.create_user(username="jkc", email="123@qq.com", password="123456")
user.save()
return HttpResponse("ok")

我们访问以上视图后,就创建了一个普通用户,查看数据库中的auth_user表,如下

创建超级用户

创建超级用户有两种方式。第一种是使用代码的方式。用代码创建超级用户跟创建普通用户非常的类似,只不过是使用create_superuser。示例代码如下:

def index(request):
user = User.objects.create_superuser(username="jkc3", email="123@qq.com", password="123456")
user.save()
return HttpResponse("ok")

也可以通过命令行的方式。命令如下:

python manage.py createsuperuser

后面就会提示你输入用户名、邮箱以及密码。

修改密码

因为密码是需要经过加密后才能存储进去的。所以如果想要修改密码,不能直接修改password字段,而需要通过调用set_password来达到修改密码的目的。示例代码如下:

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

改之前密码为$1FMDwi2zsgQu$2+8/zL6ZR43oXIvIRGfK6xrWUnv2IRjdPxVaqEwqyjM=,改完之后为$u6rNdNTvLbEG$r4TcrVsTsibcVF3ZfZIJPjLNvq73wyusLShDmpSZeKM=

登录验证

  Django的验证系统已经帮我们实现了登录验证的功能。通过django.contrib.auth.authenticate即可实现。这个方法只能通过usernamepassword来进行验证。示例代码如下:

def index(request):
user = authenticate(username="jkc", password="111111")
if user:
return HttpResponse("登录成功")
else:
return HttpResponse("登录失败")

扩展用户模型

  Django内置的User模型虽然已经足够强大了。但是有时候还是不能满足我们的需求。比如在验证用户登录的时候,他用的是用户名作为验证,而我们有时候需要通过手机号码或者邮箱来进行验证。还有比如我们想要增加一些新的字段。那么这时候我们就需要扩展用户模型了。扩展用户模型有多种方式。这里我们来一一讨论下。

继承自AbstractUser

  对于authenticate不满意,并且不想要修改原来User对象上的一些字段,但是想要增加一些字段,那么这时候可以直接继承自django.contrib.auth.models.AbstractUser,其实这个类也是django.contrib.auth.models.User的父类。比如我们想要在原来User模型的基础之上添加一个phone字段。示例代码如下:

from django.contrib.auth.base_user import BaseUserManager
from django.db import models
from django.contrib.auth.models import AbstractUser class UserManager(BaseUserManager):
use_in_migrations = True def _create_user(self,phone,password,**extra_fields):
if not phone:
raise ValueError("请填入手机号码!")
if not password:
raise ValueError('请输入密码!')
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作为USERNAME_FIELD,以后使用authenticate
# 函数验证的时候,就可以根据phone来验证,而不是原来的username
USERNAME_FIELD = 'phone'
# 提醒用户输入的字段
REQUIRED_FIELDS = [] # 重新定义Manager对象,在创建user的时候使用phone和password,而不是使用username和password
objects = UserManager()

然后再在settings中配置好AUTH_USER_MODEL=yourapp.User

注意:这种方式因为破坏了原来User模型的表结构,所以必须要在第一次migrate前就先定义好。

以上我们重新定义了User模型,新增了phone字段,并把phone作为校验字段,我们先来看下数据库的表结构



接下里我们通过createsuperuser命令来创建超级用户



我们会发现创建超级用户的时候,不再需要username字段来校验了,接下来我们验证一下登录,现在的结构需要用phone字段和密码来登录,而不是使用username,我们编写视图函数来尝试

def index(request):
# 先使用手机号密码登录
user = authenticate(username="12345678901", password="admin123")
if user:
return HttpResponse('手机号密码登录成功')
else:
return HttpResponse('手机号密码登录失败')

然后访问视图,返回手机号密码登录成功,说明现在校验的字段的内容是手机号,我们再来试试使用用户名能否登录成功

def index(request):
# 由于之前未设置username,这里先为id为1的用户设置username
user = User.objects.get(pk=1)
user.username = "jkc"
user.save()
print("保存成功")
u = authenticate(username="jkc", password="admin123")
if u:
return HttpResponse('用户名登录成功')
else:
return HttpResponse('用户名登录失败')

我们访问视图,最后返回的是手机号验证码登录失败,说明现在username校验的是手机号,我们输入用户名是校验不通过的

Django(60)Django内置User模型源码分析及自定义User的更多相关文章

  1. Django中CBV(Class Base Views)模型源码分析

    在view文件中编写一个类,并配置好路由 class Test(View): def get(self, request, *args, **kwargs): return HttpResponse( ...

  2. SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)

    Spring Boot默认使用Tomcat作为嵌入式的Servlet容器,只要引入了spring-boot-start-web依赖,则默认是用Tomcat作为Servlet容器: <depend ...

  3. Matlab.NET混合编程技巧之——直接调用Matlab内置函数(附源码)

    原文:[原创]Matlab.NET混合编程技巧之--直接调用Matlab内置函数(附源码) 在我的上一篇文章[原创]Matlab.NET混编技巧之——找出Matlab内置函数中,已经大概的介绍了mat ...

  4. asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

    原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 在前面的文章中我们曾经涉及到ControllerActionInvoker类GetPara ...

  5. Django 之 restframework 版本控制的使用以及源码分析

    Django rest_framework 之 版本控制 一.何为版本控制: ​ 用于版本的控制 二.内置的版本控制类: from rest_framework.versioning import Q ...

  6. Django(64)频率认证源码分析与自定义频率认证

    前言 有时候我们发送手机验证码,会发现1分钟只能发送1次,这是做了频率限制,限制的时间次数,都由开发者自己决定 频率认证源码分析 def check_throttles(self, request): ...

  7. Django框架(十八)—— CBV源码分析、restful规范、restframework框架

    目录 CBV源码分析.restful规范.restframework框架 一.CBV源码分析 1.url层的使用CBV 2.as_view方法 3.view方法 4.dispatch方法(可以在视图层 ...

  8. Django(50)drf异常模块源码分析

    异常模块源码入口 APIView类中dispatch方法中的:response = self.handle_exception(exc) 源码分析 我们点击handle_exception跳转,查看该 ...

  9. Django(63)drf权限源码分析与自定义权限

    前言 上一篇我们分析了认证的源码,一个请求认证通过以后,第二步就是查看权限了,drf默认是允许所有用户访问 权限源码分析 源码入口:APIView.py文件下的initial方法下的check_per ...

随机推荐

  1. Linux文件共享服务之NFS

    NFS(Network File System) 网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客户端应用可 ...

  2. hdu2604 矩阵快速幂

    题意:      给你n个人,排成一个长度是n的队伍,人只有两类f,m,问可以有多少种排法使度列中不出现fff,fmf这样的子串.思路:      一开始暴力,结果超时了,其实这个题目要是能找到类似于 ...

  3. Windows核心编程 第四章 进程(中)

    4.2 CreateProcess函数 可以用C r e a t e P r o c e s s函数创建一个进程: BOOL CreateProcessW( _In_opt_ LPCWSTR lpAp ...

  4. seccomp沙盒逃逸基础——沙盒的规则编写

    seccomp沙盒逃逸基础--沙盒的规则编写 引入: 安全计算模式 seccomp(Secure Computing Mode)是自 Linux 2.6.10 之后引入到 kernel 的特性.一切都 ...

  5. 【转】python SQLAlchemy

    数据库表是一个二维表,包含多行多列. 把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含id和name的user ...

  6. 逆向工程初步160个crackme-------7

    这两天有点发烧,被这个疫情搞得人心惶惶的.我们这里是小镇平常过年的时候人来人往的,今年就显得格外的冷清.这是老天帮让在家学习啊,破解完这个crackme明天就去接着看我的加密解密,算了算没几天就开学了 ...

  7. PlantUML --- 使用代码快速绘制时序图、思维导图

    本篇思维导图 @startmindmap <style> mindmapDiagram { .green { BackgroundColor lightgreen } .rose { Ba ...

  8. 基于虹软人脸识别,实现RTMP直播推流追踪视频中所有人脸信息(C#)

    前言 大家应该都知道几个很常见的例子,比如在张学友的演唱会,在安检通道检票时,通过人像识别系统成功识别捉了好多在逃人员,被称为逃犯克星:人行横道不遵守交通规则闯红灯的路人被人脸识别系统抓拍放在大屏上以 ...

  9. MySQL之数据定义语言(DDL)

    写在前面 本文中 [ 内容 ] 代表啊可选项,即可写可不写. SQL语言的基本功能介绍 SQL是一种结构化查询语言,主要有如下几个功能: 数据定义语言(DDL):全称Data Definition L ...

  10. [bug] Linux下执行.sh命令出现-bash: ./bin/start.sh: /bin/bash^M: bad interpreter: No such file or directory

    参考 https://www.cnblogs.com/aeolian/p/10614284.html