跳转至

自定义用户表

新项目说明

我们 通过 一个新项目:校园信息管理平台,来继续深入对 Django的学习

点击这里,查看项目的功能说明

自定义User表

Django 内置模块 contrib.auth 帮我们预置了一张用户表 user ,但是如果他不符合我们的需求,我们要重新定义,怎么办?

比如,这个项目的用户表需要新增一些字段,像 学号、备注、用户类型、真实姓名。

千万不要去改 Django 内置模块 contrib.auth.models 里面的类定义。(想一想,为什么?)

一种推荐的方式是:通过继承 contrib.auth.models 里面的 AbstractUser 类的方式

在你项目文件的 models 里面进行如下定义:

from django.contrib.auth.models import AbstractUser
from django.contrib.auth.hashers import make_password,check_password

# 可以通过 命令 python  manage.py createsuperuser 来创建超级管理员
# 就是在这User表中添加记录
class User(AbstractUser):
    id = models.BigAutoField(primary_key=True)

    # 用户类型  
    # 1: 超管 | 1000: 普通管理员  | 2000:学生  |  3000: 老师 
    usertype = models.PositiveIntegerField()

    # 真实姓名
    realname = models.CharField(max_length=30, db_index=True)

    # 学号
    studentno = models.CharField(
        max_length=10, 
        db_index=True, 
        null=True, blank=True
        )

    # 备注描述
    desc = models.CharField(max_length=500, null=True, blank=True)

    REQUIRED_FIELDS = ['usertype', 'realname']

    class Meta:
        db_table = "by_user"

这样就在原来的 contrib.auth 里面的 user表的基础上

  • 新增了 usertype、realname、phone、studentno、desc 这些字段

  • 修改了 字段 id 的类型 为 BigAuto

  • 声明了 用命令 createsuperuser 添加用户时, 'usertype','realname' 是需要提示用户填写的内容


然后,你需要告诉Django,使用这个表作为 系统的 user表。

就是 在 settings.py 中,添加如下设置

AUTH_USER_MODEL = 'myapp.User'

其中 myapp 改为你的 User 定义 所在的 django app 名称

一定要确保 这个 myapp 在你的 INSTALLED_APPS 里面设置了。


可能你会奇怪,我们为什么不能重新完全的重定义 User 表,一定要继承 contrib.auth.models 里面的 AbstractUser 类呢?

那是因为 Django内置的 认证 、权限 、 Session 机制 和 auth 模块深度绑定了,如果你需要使用 这些机制提供的方法,就不能抛弃 auth 里面的 user 表。

如果你不打算使用 Django内置的 认证 或者 Session 机制, 完全可以自己定义一张 User表。

那样,你就需要自己编写 认证流程 和 用户访问有效性的检查机制(比如基于 jwt token)了。

用户表中的 password

Django 的 用户表中 password 字段是需要特殊处理的。

Django 的密码不是明文存储的, 有好几种方式。具体说明,点击这里参考官方文档

我们可以使用 Django 库提供的方法 产生 password 字段值(通常是hash处理过)

from django.contrib.auth.hashers import make_password,check_password

# 添加一条记录
user = User.objects.create(
    username  = username,
    # 使用 make_password 函数 产生password字段
    password  = make_password(data['password']),
    # 其他字段...)


使用 Django auth 库里面的 authenticate 方法 就包含了 校验用户名、密码的过程,如下

from django.contrib.auth import authenticate, login, logout

# 使用 Django auth 库里面的 方法校验用户名、密码
user = authenticate(username=userName, password=passWord)


但是,有的系统设计完全弃用了 Django 的 auth、session 机制,我们仍然可以使用 hashers库里面的 check_password 方法 校验密码,如下

from django.contrib.auth.hashers import make_password,check_password

# 检查密码
if not check_password('密码明文', user.password):
    return JsonResponse({'retcode': 1, 'msg': '密码错误'})

数据操作移到models中

为了实现后端系统的功能合理划分,建议把业务逻辑放在 view 代码中,而把数据底层处理放在 models中国。

这样, 处理HTTP请求的 view代码,只需要调用 models中的方法即可。

比如,处理 添加用户的view

def adduser(request):

    # 从请求消息中 获取要添加客户的信息
    # 并且插入到数据库中

    data = request.param_dict['data']

    # 直接调用 models中的添加 用户 的代码    
    ret = User.add(data)

    return  JsonResponse(ret)

而 models中 真正实现添加功能,如下

class User(AbstractUser):
    id = models.BigAutoField(primary_key=True)
    usertype = models.PositiveIntegerField()
    realname = models.CharField(max_length=30, db_index=True)

    class Meta:
        db_table = "cimp_user"

    # 直接在Model中用静态方法定义数据操作
    @staticmethod
    def add(data,usertype):

        try:
            username = data['username']
            if User.objects.filter(username=username).exists():
                return {'ret': 1, 'msg': f'登录名 {username} 已经存在'}

            user = User.objects.create(
                    username  = username,
                    password  = make_password(data['password']),
                    usertype  = usertype,
                    realname  = data['realname'],
                    studentno = data['studentno'],
                    desc      = data['desc']
                )

            return {'ret': 0,'id': user.id}