Django自定义用户类User Model的两种方式

目录

一、使用AbstractUser类自定义User Model

二、使用AbstractBaseUser和PermissionsMixin自定义User Model


在Django中有给我们提供了一个默认的User Model,不进行任何修改时,创建的user表字段如下:

 

  • username:用户名
  • email: 电子邮件
  • password:密码
  • first_name:名
  • last_name:姓
  • is_active: 是否为活跃用户。默认是True
  • is_staff: 是否为员工。默认是False
  • is_superuser: 是否为管理员。默认是False
  • date_joined: 加入日期。系统自动生成。

 

其中在注册时,usernameemailpassword是必填的三个字段。

 

默认User Model给我们带来了好处的同时,也带来诸多不便:

 

  • 无法拓展自己想要的其他字段,如nickname(昵称),birthday(出生年月)等
  • 无法修改默认的登录注册逻辑,默认的user类中需要同时传用户名、邮箱和密码三个字段,但有时候我们并不需要邮箱字段,而是采用手机号注册登录的方式。
  • 无法修改已有字段的形式,如默认的user类中有first_namelast_name字段,分别存储用户的名和姓,但对于我们Chinese People,我们更习惯姓名一起填写,因此这种字段分法比较的麻烦。

 

针对以上情况,我们的解决方法是进行自定义一个用户类,修改并拓展其功能。

 

自定义用户类的方法有两种,一是基于AbstractUser类进行自定义,另一种是基于AbstractBaseUserPermissionsMixin两个类进行自定义。下面两种方法都会介绍。

 

 

一、使用AbstractUser类自定义User Model

 

首先我们了解AbstractUser中包含哪些字段:

 

  • username:用户名
  • email: 电子邮件
  • password:密码
  • first_name:名
  • last_name:姓
  • is_active: 是否为活跃用户。默认是True
  • is_staff: 是否为员工。默认是False
  • is_superuser: 是否为管理员。默认是False
  • date_joined: 加入日期。系统自动生成。

 

芜湖,你会发现,AbstractUser类的字段就是默认User类所含的所有字段。没错,AbstractUser类的作用就是让你对用户类进行拓展的。

 

AbstractUser类用于拓展Django自带的User类字段,而不能修改其已有字段。

 

假设现在自定义一个user类,需要增加nicknamegenderbirthday字段,并将user表的名称定义为users

 

首先新建一个app,名为users,并在settings里添加此app配置

 

django-admin startapp users

 

在settings.py中添加此app

 

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users.apps.UsersConfig',
]

 

users model.py代码如下:

 

from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
    nickname = models.CharField(verbose_name="昵称", max_length=20, null=True)
    gender = models.CharField(verbose_name="性别", choices=(("male", "先生"), ("female", "女士")), max_length=6,null=True)
    birthday = models.DateField(verbose_name="出身年月", blank=True, null=True)

    class Meta:
        verbose_name = "用户"
        verbose_name_plural = verbose_name
        db_table = "users"

    def __str__(self):
        return self.username

 

在models.py里定义一个User类,继承自AbstractUser,随后在其中定义三个新增字段,使用内部类Meta定义这个用户类的元信息,其中db_table定义在数据库创建该表时的表名为什么,不指定默认为django_user,其中user为内部类的父类类名。

 

这样就完成了自定义用户类的定义。

 

但还没完。

 

我们还需要在settings.py里配置一下默认的用户类,否则Django依旧使用其自带的user model。

 

AUTH_USER_MODEL = "users.User"

 

如此一来就大功告成,在manage shell中进行migrate操作同步到数据库。

 

django-admin makemigrations users
django-admin migrate users

 

完成。

 

二、使用AbstractBaseUser和PermissionsMixin自定义User Model

 

其实翻看一下AbstractUser的源代码,你发现一个情况:

 

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    """
    An abstract base class implementing a fully featured User model with
    admin-compliant permissions.

    Username and password are required. Other fields are optional.
    """
    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 = UserManager()

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'username'
    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 the first_name plus the 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 short name for the user."""
        return self.first_name

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

 

你会发现,AbstractUser它竟然也是有继承的。它继承的就是我们接下来要说的AbstractBaseUserPermissionsMixin两个类。

 

同时它还设置了一些字段指定行为和一个对象指定行为:

 

objects = UserManager()
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']

 

这部分稍后再讲,先讲解它继承的两个父类。

 

AbstractBaseUserPermissionsMixin分别定义了用户类最基本的字段以及最基本的权限字段,可以说这两个类是Django中user类最核心的部分了,缩无可缩。

 

查看AbstractBaseUser的源代码,你会发现这个类中定义了如下几个字段:

 

  • password,密码
  • last_login,最后登录时间

 

而在PermissionsMixin中,定义了如下几个字段:

 

  • is_super,是否是超级管理员
  • groups,所属用户组
  • user_permissions,用户权限组

 

由此可见,使用AbstractBaseUserPermissionsMixin自定义用户类的自由度是最高的,只需要继承5个字段即可,其他的可以完全由我们自定义。

 

但使用这两个类定义用户组的时候需要在自定义类中额外配置一些信息。

 

下面举个例子。

 

定义一个自定义用户类,要求使用手机号作为用户名进行注册,去除邮箱、姓和名字段,增加昵称,真实姓名,用户头像,出生年月,性别,创建时间等字段。

 

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
class Users(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(verbose_name="用户名", primary_key=True, max_length=20, unique=True)
    nickname = models.CharField(verbose_name="昵称", max_length=20, blank=True, null=True)
    real_name = models.CharField(verbose_name="真实姓名", max_length=20, null=True, blank=True)
    image = models.ImageField(verbose_name="头像", storage=OssStorage("user/portrait"), blank=True, null=True,
                              max_length=2048)
    create_time = models.DateTimeField(verbose_name="创建时间", default=datetime.now)
    update_time = models.DateTimeField(verbose_name="更新时间", default=datetime.now)
    is_active = models.BooleanField(verbose_name="是否有效", default=True, blank=True, null=True)
    is_staff = models.BooleanField(verbose_name="是否是员工", default=False)
    is_superuser = models.BooleanField(verbose_name="是否是超级管理员", default=False)
    USERNAME_FIELD = "username"
    objects = MyMgr()

    @property
    def image_url(self):
        if self.image and hasattr(self.image, 'url'):
            return self.image.url
        return ''

    class Meta:
        verbose_name = "用户"
        verbose_name_plural = verbose_name
        db_table = 'users'

    def clean(self):
        super().clean()

    def __str__(self):
        return "{}({})".format(self.username, self.nickname)

    def get_short_name(self):
        """Return the short name for the user."""
        return self.nickname

    def getImage(self):
        return format_html('<img src="{}" style="width:50px;height:auto">', self.image_url)

    getImage.short_description = "头像显示"

 

分析代码,会发现,我们除了定义相关字段外,还进行了字段指定行为和一个对象指定行为:

 

USERNAME_FIELD = "username"
objects = MyMgr()

 

其中USERNAME_FIELD = "username"表示该model类中用哪个字段表示用户名。这个字段指定行为是必要操作,用于Django验证用户名密码以及后台登录等操作。

 

objects = MyMgr()是一种对象指定行为,主要目的是自定义在使用django-admin创建用户的时候Django的处理逻辑,其中MyMgr是自定义的一个管理类,代码如下:

 

from django.contrib.auth.models import BaseUserManager
class MyMgr(BaseUserManager):
    def create_user(self, username, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not username:
            raise ValueError('Users must have an username')

        user = self.model(
            username=username,
        )
        user.set_password(password)
        user.is_active = True
        user.is_staff = True
        user.save(using=self._db)
        return user

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

 

这个管理类中重载了两个函数,分别是create_usercreate_superuser,分别定义了创建普通用户以及超级管理员用户的情况,在使用django-admin创建用户时将触发其中的业务逻辑,具体的实现逻辑根据各自定义的字段实现,这里就不阐述了。

 

在自定义Users中,还涉及到了诸如Image字段以及自定义Stroge等操作,这里不作讲解,大家可以看另一篇教程《Django自定义Storage实现图片上传至各大OSS》

 

最后,同样在settings里指定默认的用户类:

 

AUTH_USER_MODEL = "users.User"

 

然后在django shell中执行migrate操作:

 

django-admin makemigrations users
django-admin migrate users

 

至此,第二种自定义user类的方法也大功告成。相对于第一种自定义方法,第二种复杂了许多,但是第二种可以实现更加自由地进行用户类的自定义。

 

此外,我们还可以对Django中用户密码的生成和验证逻辑进行自定义,实现使用自定义算法的用户密码生成与验证,具体请看《Django自定义用户密码的生成与验证》

 

Over.

 

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
Django 中,可以使用 Django 自带的 `make_password` 函数来对用户密码进行加密,也可以使用自定义的加密方式。 使用 Django 自带的加密方式: ```python from django.contrib.auth.hashers import make_password password = 'my_password' hashed_password = make_password(password) ``` 使用自定义的加密方式: ```python import hashlib password = 'my_password' hashed_password = hashlib.sha256(password.encode('utf-8')).hexdigest() ``` 将加密后的密码保存到用户模型中: ```python from django.contrib.auth.models import AbstractBaseUser, BaseUserManager class MyUserManager(BaseUserManager): 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.password = make_password(password) user.save(using=self._db) return user def create_superuser(self, email, password): user = self.create_user(email=email, password=password) user.is_admin = True user.save(using=self._db) return user class MyUser(AbstractBaseUser): email = models.EmailField(unique=True) password = models.CharField(max_length=128) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) objects = MyUserManager() USERNAME_FIELD = 'email' def has_perm(self, perm, obj=None): return True def has_module_perms(self, app_label): return True @property def is_staff(self): return self.is_admin ``` 在上面的示例中,我们使用 `make_password` 函数将密码加密后保存到了用户模型中的 `password` 字段中。如果你使用的是自定义的加密方式,需要将加密后的密码保存到 `password` 字段中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FatBallFish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值