赞
踩
目录
一、使用AbstractUser类自定义User Model
二、使用AbstractBaseUser和PermissionsMixin自定义User Model
在Django中有给我们提供了一个默认的User Model,不进行任何修改时,创建的user表字段如下:
其中在注册时,username
,email
和password
是必填的三个字段。
默认User Model给我们带来了好处的同时,也带来诸多不便:
nickname
(昵称),birthday
(出生年月)等first_name
和last_name
字段,分别存储用户的名和姓,但对于我们Chinese People,我们更习惯姓名一起填写,因此这种字段分法比较的麻烦。
针对以上情况,我们的解决方法是进行自定义一个用户类,修改并拓展其功能。
自定义用户类的方法有两种,一是基于AbstractUser
类进行自定义,另一种是基于AbstractBaseUser
和PermissionsMixin
两个类进行自定义。下面两种方法都会介绍。
首先我们了解AbstractUser
中包含哪些字段:
芜湖,你会发现,AbstractUser
类的字段就是默认User类所含的所有字段。没错,AbstractUser
类的作用就是让你对用户类进行拓展的。
AbstractUser类用于拓展Django自带的User类字段,而不能修改其已有字段。
假设现在自定义一个user类,需要增加nickname
、gender
和birthday
字段,并将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
完成。
其实翻看一下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
它竟然也是有继承的。它继承的就是我们接下来要说的AbstractBaseUser
和PermissionsMixin
两个类。
同时它还设置了一些字段指定行为和一个对象指定行为:
- objects = UserManager()
- EMAIL_FIELD = 'email'
- USERNAME_FIELD = 'username'
- REQUIRED_FIELDS = ['email']
这部分稍后再讲,先讲解它继承的两个父类。
AbstractBaseUser
和PermissionsMixin
分别定义了用户类最基本的字段以及最基本的权限字段,可以说这两个类是Django中user类最核心的部分了,缩无可缩。
查看AbstractBaseUser
的源代码,你会发现这个类中定义了如下几个字段:
而在PermissionsMixin
中,定义了如下几个字段:
由此可见,使用AbstractBaseUser
和PermissionsMixin
自定义用户类的自由度是最高的,只需要继承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_user
和create_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.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。