广州番禺Python, Java小班周末班培训
薯条老师在广州做Python和Java的小班培训,一个班最多10人,学员的平均就业薪资有11K。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。培训的课程有Python爬虫,Python后端开发,Python办公自动化,Python大数据分析,Python量化投资,Python机器学习,Java中高级后端开发。授课详情请点击:http://chipscoco.com/?cate=6
9.3.1 对用户模型进行扩展
django内置的用户模型只提供了有限的字段,例如用户的账号名,密码,邮件等,添加额外的字段和操作方法时需要对用户模型进行扩展。
本节重点介绍对用户模型进行扩展的三种方法:
(1) 从AbstractUser中派生子类进行扩展
(2) 使用OneToOneField与信号进行扩展
(3) 从AbstractBaseUser中派生子类进行扩展
9.3.2 从AbstractUser中派生子类
打开django.contrib.auth路径下的models.py,可以找到User模型的源码:
class User(AbstractUser): """ Users within the django authentication system are represented by this model. Username and password are required. Other fields are optional. """ class Meta(AbstractUser.Meta): swappable = 'AUTH_USER_MODEL'
上文代码中的MyUser即为我们新定义的用户模型,如需新增一个手机号的字段,则直接在模型中添加相应的字段即可。举一个简单的例子,在MyUser中扩展一个手机号字段,代码如下:
# 导出AbstractUser类 from django.contrib.auth.models import AbstractUser class MyUser(AbstractUser): # 新增一个手机号phone_number phone_number = models.CharField(max_length = 11, blank=True) class Meta(AbstractUser.Meta): swappable = 'AUTH_USER_MODEL'
这样就实现了扩展。以MySQL为例,我们可以进入MySQL交互模式,查看数据表blog_myuser的所有字段:
从输出可以分析出,我们为内置的User模型扩展了一个名为phone_number的字段。User模型默认使用名为username的字段进行登录认证,我们在对User模型进行扩展时,可以通过USERNAME_FIELD属性来指定登录认证的字段。
代码实例-使用手机号作为username进行登录认证:
# 导出AbstractUser类 from django.contrib.auth.models import AbstractUser class MyUser(AbstractUser): # 新增一个手机号phone_number phone_number = models.CharField(max_length = 11, blank=True) # 采用手机号+密码的方式进行登录认证 USERNAME_FIELD = "phone_number" class Meta(AbstractUser.Meta): swappable = 'AUTH_USER_MODEL'
对User模型进行扩展以后,需要在settings.py中修改全局变量AUTH_USER_MODEL的值,以告诉django, 使用新的用户模型来表示用户。AUTH_USER_MODEL的输出格式:
'app.MyUser'
app表示django应用的名称,MyUser为自定义的用户模型名。假设django应用名为chipscoco, 扩展的用户模型为MyUser, 则AUTH_USER_MODEL的值为:
'chipscoco.MyUser'
由于在模型中新增了用户模型,故还需要使用makemigrations和migrate命令进行模型迁移。django的后台管理系统中使用的仍是旧的User模型,此时还需要在django应用的admin.py中对扩展的用户模型进行注册。
代码实例:
from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import MyUser admin.site.register(MyUser, UserAdmin)
至此完成了用户模型的扩展。
在项目中使用AbstractUser派生子类进行扩展,需要在首次数据迁移的时候就定义好扩展的用户模型。
9.3.3 使用OneToOneField与信号进行扩展
使用OneToOneField进行扩展,是指将内置的User模型作为主表,然后将扩展的字段定义在从表中。在models.py中定义一个用来进行字段扩展的从表,代码实例:
from django.contrib.auth.models import User from django.db import models # 定义一个UserExtension模型,作为User模型的从表 class UserExtension(models.Model): # 此行代码为关键,将User模型与UserExtension模型定义为一对一的外键关系,关联字段别名为extension user = models.OneToOneField(User,on_delete=models.CASCADE, related_name='extension') # 在从表中进行扩展,新增一个phone_number字段 phone_number = models.CharField(blank=True)
定义完从表以后,需要再定义一个信号处理器,即当User对象执行save方法以后,可以自动地执行扩展对象的创建。信号处理器的代码实例:
from django.dispatch import receiver from django.db.models.signals import post_save @receiver(post_save,sender=User) def create_user_extension(sender,instance,created,**kwargs): # 在信号接收器内部创建扩展的用户对象 if created: UserExtension.objects.create(user=instance) else: instance.extension.save()
在上文代码中使用@receiver装饰器来定义一个信号接收器,sender参数传递的为信号发送的对象,post_save表示User对象执行完save方法后才发送信号。视图中的代码实例:
from django.http import JsonResponse from django.contrib.auth.models import User def register(request): if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") user = User.objects.create_user(username=username,password=password) # 通过用户对象的关联字段extension来为扩展的字段赋值 user.extension.phone_number = request.POST.get("phone_number","") user.save() # user对象执行完save方法后,会将信号发送给create_user_extension方法 # 在create_user_extension内部会创建扩展的用户对象 return JsonResponse("注册成功")
以OneToOneField的方式扩展以后,如需将扩展字段作为登录认证字段,该如何操作呢?以手机号为例,可以在User模型中通过关联字段反向查询用户对象,然后再调用用户对象的验证方法。
例如执行User.objects.filter(extension__phone_number="xx").first()获取到与扩展字段phone_number对应的用户对象,再通过用户对象的check_password方法验证密码是否正确 。
9.3.4 从AbstractBaseUser中派生子类进行扩展
前面两种用户模型的扩展方法都比较简单,如需修改默认的验证方式,且只保留新定义的字段,那么应该从AbstractBaseUser中继承一个子类。使用AbstractBaseUser进行扩展的核心流程:
(1) 定义用户模型的管理器
用户模型的管理器负责用户对象的创建,定义用户模型的管理器,需要从BaseUserManager中进行继承,并覆盖create_user以及create_superuser方法。现在对管理器进行扩展,使得在创建用户时必须传递一个电话号码的参数,以下代码定义在models.py中:
from django.contrib.auth.models import BaseUserManager class MyUserManager(BaseUserManager): def create_user(self, username, phone_number, password=None): """ 对管理器方法进行扩展,使用用户名,电话号码,密码来创建用户对象 """ if not phone_number: raise ValueError('用户必须有一个手机号') # 构造一个用户对象 user = self.model( phone_number=phone_number, username=username) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, username, phone_number, password=None): """ 参数同create_user,创建一个管理员用户 """ user = self.create_user( username, phone_number=phone_number, password=password,) user.is_admin = True user.save(using=self._db) return user
(2) 从AbstractBaseUser进行继承,扩展其属性或方法
AbstractBaseUser的主要属性:
属性名 | 描述
|
USERNAME_FIELD | 用户的账号认证字段,默认使用username进行认证 |
EMAIL_FIELD | 用户的邮箱地址 |
REQUIRED_FIELDS | 使用createsuperuser命令来创建用户时的提示字段,使用REQUIRED_FIELDS时无需添加USERNAME_FIELD定义的字段和password字段,django会自动将其进行提示。 |
is_active | 布尔类型,指示用户是否已激活 |
现在从AbastractBaseUser中进行继承,并扩展一个phone_number字段,以下代码定义在models.py中:
from django.contrib.auth.models import AbstractBaseUser class MyUser(AbstractBaseUser): # 扩展一个phone_number字段 phone_number = models.CharField(max_length=11) email = models.EmailField() is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) # 将objects赋值为我们在上文中定义的管理器对象 objects = MyUserManager() # 使用手机号来作为认证字段 USERNAME_FIELD = 'phone_number' # 执行createsuperuser命令时,将用户的邮箱地址作为提示 REQUIRED_FIELDS = ['email'] def __str__(self): return self.email def has_perm(self, perm, obj=None): # 通过该方法来获取用户是否有指定的权限 return True def has_module_perms(self, app_label): # 通过方法来判断用户是否有app_label的view权限 return True @property def is_staff(self): # 默认情况下管理员都可以访问后台管理系统 return self.is_admin
在完成了(1)与(2)步的操作以后,如需使用后台管理系统管理用户,那么需要在admin.py中将自定义的用户模型进行注册,并修改后台系统的用户管理表单:
# 导出forms,重定义后台系统的用户管理表单 from django import forms from django.contrib import admin from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.forms import ReadOnlyPasswordHashField # 从modes.py中导出我们自定义的用户模型 from .models import MyUser # 定义用户的创建表单 class UserCreationForm(forms.ModelForm): """创建用户的表单,包含所有必需的字段,外加一个需重复输入的密码字段""" password1 = forms.CharField(label='输入密码', widget=forms.PasswordInput) password2 = forms.CharField(label='确认密码', widget=forms.PasswordInput) class Meta: model = MyUser fields = ('username', 'phone_number','email') def clean_password2(self): # 检查两次输入的密码是否匹配 password1 = self.cleaned_data.get("password1") password2 = self.cleaned_data.get("password2") if not password1 or not password2 or (password1 != password2): raise forms.ValidationError("密码不相等") return password2 def save(self, commit=True): # 以哈希字符串的形式来保存用户的密码 user = super().save(commit=False) user.set_password(self.cleaned_data["password1"]) if commit: user.save() return user # 定义用户的编辑表单 class UserChangeForm(forms.ModelForm): """ 用来对用户的信息进行编辑 """ # 显示用户的密码时,将其设置为只读的哈希字段 password = ReadOnlyPasswordHashField() class Meta: model = MyUser # 定义用户模型在编辑页中出现的字段 fields = ('username', 'password', 'phone_number','email', 'is_active', 'is_admin') def clean_password(self): # 不论用户输入什么都返回密码的输入值 # 在编辑页中进行操作,而非对密码字段进行操作 # 因为密码字段无法访问密码的原始值 return self.initial["password"] class UserAdmin(BaseUserAdmin): # 定义用户的编辑页表单和创建表单 form = UserChangeForm add_form = UserCreationForm list_display = ('phone_number', 'username', 'is_admin') list_filter = ('is_admin',) fieldsets = ( (None, {'fields': ('phone_number', 'password')}), ('个人信息', {'fields': ('username','email')}), ('权限', {'fields': ('is_admin',)}),) add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('phone_number', 'password1', 'password2')} ),) search_fields = ('phone_number',) ordering = ('phone_number',) filter_horizontal = () # 注册自定义的用户模型 admin.site.register(MyUser, UserAdmin) # 由于我们在自定义的用户模型中并未使用django内置的权限 # 所以要取消Group模型的注册 admin.site.unregister(Group)
从AbstractBaseUser中派生子类后,同样需要在settings.py中进行配置,具体的配置方法可参考9.3.1 从AbstractUser中派生子类的内容。
9.3.5 最具实力的小班培训
薯条老师在广州做Python和Java的小班培训,一个班最多10人。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。打算参加小班培训的同学,必须遵守薯条老师的学习安排,认真做作业和项目。把知识学好,学扎实,那么找到一份高薪的工作就是很简单的一件事。
(1) Python后端工程师高薪就业班,月薪11K-18K,免费领取课程大纲
(2) Python爬虫工程师高薪就业班,年薪十五万,包拿Offer
(3) 数据分析高薪就业班,月薪11K-15K, 免费领取课程大纲
(4) Python大数据挖掘,量化投资就业班,月薪12K-25K,免费领取课程大纲
扫码免费领取Python学习资料: