当前位置:   article > 正文

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

username_field

目录

一、使用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

 

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'users.apps.UsersConfig',
  9. ]

 

users model.py代码如下:

 

  1. from django.db import models
  2. from django.contrib.auth.models import AbstractUser
  3. class User(AbstractUser):
  4. nickname = models.CharField(verbose_name="昵称", max_length=20, null=True)
  5. gender = models.CharField(verbose_name="性别", choices=(("male", "先生"), ("female", "女士")), max_length=6,null=True)
  6. birthday = models.DateField(verbose_name="出身年月", blank=True, null=True)
  7. class Meta:
  8. verbose_name = "用户"
  9. verbose_name_plural = verbose_name
  10. db_table = "users"
  11. def __str__(self):
  12. 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操作同步到数据库。

 

  1. django-admin makemigrations users
  2. django-admin migrate users

 

完成。

 

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

 

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

 

  1. class AbstractUser(AbstractBaseUser, PermissionsMixin):
  2. """
  3. An abstract base class implementing a fully featured User model with
  4. admin-compliant permissions.
  5. Username and password are required. Other fields are optional.
  6. """
  7. username_validator = UnicodeUsernameValidator()
  8. username = models.CharField(
  9. _('username'),
  10. max_length=150,
  11. unique=True,
  12. help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
  13. validators=[username_validator],
  14. error_messages={
  15. 'unique': _("A user with that username already exists."),
  16. },
  17. )
  18. first_name = models.CharField(_('first name'), max_length=30, blank=True)
  19. last_name = models.CharField(_('last name'), max_length=150, blank=True)
  20. email = models.EmailField(_('email address'), blank=True)
  21. is_staff = models.BooleanField(
  22. _('staff status'),
  23. default=False,
  24. help_text=_('Designates whether the user can log into this admin site.'),
  25. )
  26. is_active = models.BooleanField(
  27. _('active'),
  28. default=True,
  29. help_text=_(
  30. 'Designates whether this user should be treated as active. '
  31. 'Unselect this instead of deleting accounts.'
  32. ),
  33. )
  34. date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
  35. objects = UserManager()
  36. EMAIL_FIELD = 'email'
  37. USERNAME_FIELD = 'username'
  38. REQUIRED_FIELDS = ['email']
  39. class Meta:
  40. verbose_name = _('user')
  41. verbose_name_plural = _('users')
  42. abstract = True
  43. def clean(self):
  44. super().clean()
  45. self.email = self.__class__.objects.normalize_email(self.email)
  46. def get_full_name(self):
  47. """
  48. Return the first_name plus the last_name, with a space in between.
  49. """
  50. full_name = '%s %s' % (self.first_name, self.last_name)
  51. return full_name.strip()
  52. def get_short_name(self):
  53. """Return the short name for the user."""
  54. return self.first_name
  55. def email_user(self, subject, message, from_email=None, **kwargs):
  56. """Send an email to this user."""
  57. send_mail(subject, message, from_email, [self.email], **kwargs)

 

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

 

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

 

  1. objects = UserManager()
  2. EMAIL_FIELD = 'email'
  3. USERNAME_FIELD = 'username'
  4. REQUIRED_FIELDS = ['email']

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

下面举个例子。

 

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

 

  1. from django.db import models
  2. from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
  3. class Users(AbstractBaseUser, PermissionsMixin):
  4. username = models.CharField(verbose_name="用户名", primary_key=True, max_length=20, unique=True)
  5. nickname = models.CharField(verbose_name="昵称", max_length=20, blank=True, null=True)
  6. real_name = models.CharField(verbose_name="真实姓名", max_length=20, null=True, blank=True)
  7. image = models.ImageField(verbose_name="头像", storage=OssStorage("user/portrait"), blank=True, null=True,
  8. max_length=2048)
  9. create_time = models.DateTimeField(verbose_name="创建时间", default=datetime.now)
  10. update_time = models.DateTimeField(verbose_name="更新时间", default=datetime.now)
  11. is_active = models.BooleanField(verbose_name="是否有效", default=True, blank=True, null=True)
  12. is_staff = models.BooleanField(verbose_name="是否是员工", default=False)
  13. is_superuser = models.BooleanField(verbose_name="是否是超级管理员", default=False)
  14. USERNAME_FIELD = "username"
  15. objects = MyMgr()
  16. @property
  17. def image_url(self):
  18. if self.image and hasattr(self.image, 'url'):
  19. return self.image.url
  20. return ''
  21. class Meta:
  22. verbose_name = "用户"
  23. verbose_name_plural = verbose_name
  24. db_table = 'users'
  25. def clean(self):
  26. super().clean()
  27. def __str__(self):
  28. return "{}({})".format(self.username, self.nickname)
  29. def get_short_name(self):
  30. """Return the short name for the user."""
  31. return self.nickname
  32. def getImage(self):
  33. return format_html('<img src="{}" style="width:50px;height:auto">', self.image_url)
  34. getImage.short_description = "头像显示"

 

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

 

  1. USERNAME_FIELD = "username"
  2. objects = MyMgr()

 

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

 

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

 

  1. from django.contrib.auth.models import BaseUserManager
  2. class MyMgr(BaseUserManager):
  3. def create_user(self, username, password=None):
  4. """
  5. Creates and saves a User with the given email, date of
  6. birth and password.
  7. """
  8. if not username:
  9. raise ValueError('Users must have an username')
  10. user = self.model(
  11. username=username,
  12. )
  13. user.set_password(password)
  14. user.is_active = True
  15. user.is_staff = True
  16. user.save(using=self._db)
  17. return user
  18. def create_superuser(self, username, password=None):
  19. """
  20. Creates and saves a superuser with the given email, date of
  21. birth and password.
  22. """
  23. user = self.create_user(
  24. username,
  25. password=password,
  26. )
  27. user.is_admin = True
  28. user.is_staff = True
  29. user.is_superuser = True
  30. user.save(using=self._db)
  31. return user

 

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

 

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

 

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

 

AUTH_USER_MODEL = "users.User"

 

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

 

  1. django-admin makemigrations users
  2. django-admin migrate users

 

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

 

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

 

Over.

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/306398
推荐阅读
相关标签
  

闽ICP备14008679号