Django User 模块之 AbstractUser 扩展详解


Posted in Python onMarch 11, 2020

最近在写博客,刚好写到用户注册注销模块,觉得这一方面还是挺有趣的。当尝试掀开 Django 的源代码时一切 API 就不会变得那么摸不着。顺着读Django 的各模块源码,我们可以更灵活地更改代码以实现自己想要的功能。

现在,思考一个问题,主需求是实现博客中用户的注册登录登出功能。如果只满足于用户注册时只登记其邮箱或是用户名,Django 自带的 User 模块既可以实现。但实际上,一个普遍的要求是注册用户应该能够修改自己的头像信息,邮箱信息,昵称信息等其他更灵活的需求。

可以先看一下 Django User 模块的源码

class User(AbstractUser):
  """
  Users within the Django authentication system are represented by this
  model.

  Username, password and email are required. Other fields are optional.
  """
  class Meta(AbstractUser.Meta):
    swappable = 'AUTH_USER_MODEL'

注意:如果你的是 Anaconda 管理,可以在路径 C:\Users\User\Anaconda3\Lib\site-packages\django\contrib\auth\models.py 查看

Django 中的 User 模块实际上继承了 AbstractUser 模块,AbstractUser 模块下有 :

username
first_name
last_name
email
date_joined

你可以看出,User 模块继承了 AbstractUser 抽象基类,而仅仅只是继承了,并没有对 AbstractUser 进行任何扩展。所以,对于一个需要更多需求的 User 模块信息来说,我们可以继承 AbstractUser 并根据自己的需求进行扩展。

现在,我们对用户属性添加一些需求,比如支持用户修改头像、支持用户昵称、qq、wechat 以及网站链接等。

class User(AbstractUser):
  nickname = models.CharField(max_length=30, blank=True, null=True, verbose_name='昵称')
  qq = models.CharField(max_length=20, blank=True, null=True, verbose_name='QQ号码')
  url = models.URLField(max_length=100, blank=True, null=True, verbose_name='个人网页地址')
  avatar = ProcessedImageField(upload_to='avatar',
default='avatar/default.png', verbose_name='头像')

  class Meta:
    verbose_name = '用户'
    verbose_name_plural = verbose_name
    ordering = ['-id']

  def __str__(self):
    return self.username

我们给自定义的用户模块增加 nickname(昵称), qq, url(网站链接),avatar(头像)属性。

注意:为了让 Django 能够识别使用自定义的用户模型,必须要在 settings.py 中设置自定义模块位置,如在 settings.py 上添加

AUTH_USER_MODEL = 'blog.user'

其中,blog 为你对应的应用 app 信息,user 为 blog 应用下的 user 模块,在这里 blog 和 user 大小写无关。

如果在你现在执行数据库迁移命令,可能会出现 blog 不存在 user 模块 的提示,而无法重新进行数据迁移。

ValueError: The field account.EmailAddress.user was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.
The field admin.LogEntry.user was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.
The field blog.Article.author was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.
The field easy_comment.Comment.user was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.
The field easy_comment.Like.user was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.
The field notifications.Notification.recipient was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.
The field online_status.OnlineStatus.user was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.
The field socialaccount.SocialAccount.user was declared with a lazy reference to 'blog.user', but app 'blog' doesn't provide model 'user'.

所以,如果之前是使用例如 AUTH_USER_MODEL = auth.user 的用户模型,并重新将其自定义为 AUTH_USER_MODEL = blog.user 请删掉 migrations 目录下的所有文件 以及数据库文件。

删除之后,重新进行数据库的迁移

$ python manage.py makemigrations myapp
$ python manage.py migrate

这个时候,所使用的用户即为自定义后的用户了。

File "C:\Users\Micky\Anaconda3\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
  return self.cursor.execute(sql, params)
 File "C:\Users\Micky\Anaconda3\lib\site-packages\django\db\backends\sqlite3\base.py", line 303, in execute
  return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such table: blog_user

这里可以在模板中指定数据库 db_table = 'user'

补充知识:Django学习笔记——内置用户类AbstractUser与内置认证校验系统

内置用户类AbstractUser

我们在之前讲过了model模型的作用和父类的作用,这次介绍的内置用户类AbstractUser就是Django内置的一个关于用户操作的类,它极大地方便了我们对model模型中对User用户类的设计。而所谓内置用户类的本质也就是一个封装好的父类,所以使用起来是相当的方便。

#导入AbstractUser类
from django.contrib.auth.models import AbstractUser

#直接继承就可以了,如果有需要就向寻常model一样写字段就可以
class User(AbstractUser):
  pass

我们通过查看AbstractUser的源码可以知道它设有几个字段

#用户名
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)

内置认证校验系统

django自带的用户认证校验系统较为简单,主要就是认证用户名密码的正确与否

首先要在settings里面配置

#使用自带的认证系统
AUTH_USER_MODEL = "user.User"

这是配合自带的用户类AbstractUser一起使用的

通常使用在类视图中的post方法校验用户登录等操作

在view中的具体代码如下

class LoginView(View):

  def get(self,request):
    #逻辑代码
    return render(request,'login.html')

  def post(self,request):
    # 获取前端传递过来的用户名和密码
    username = request.POST.get('username')
    pwd = request.POST.get('pwd')
    record = request.POST.get('record')
    # 进行数据校验
    if not all([username,pwd]):
      return HttpResponse('数据输入不完整')
    # 验证用户名和密码是否正确
    user = authenticate(username=username,password=pwd)
    return render(request,''index.html')

主要就是其中的user = authenticate(username=username,password=pwd)

两个参数都是拿到前端用户输入的信息

以上这篇Django User 模块之 AbstractUser 扩展详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python交互式图形编程实例(二)
Nov 17 Python
Python实现将一个正整数分解质因数的方法分析
Dec 14 Python
numpy 计算两个数组重复程度的方法
Nov 07 Python
对Python模块导入时全局变量__all__的作用详解
Jan 11 Python
Python中Unittest框架的具体使用
Aug 27 Python
python数据化运营的重要意义
Nov 25 Python
Pandas时间序列:重采样及频率转换方式
Dec 26 Python
python-OpenCV 实现将数组转换成灰度图和彩图
Jan 09 Python
用Python开发app后端有优势吗
Jun 29 Python
Keras搭建自编码器操作
Jul 03 Python
Python Charles抓包配置实现流程图解
Sep 29 Python
python 判断字符串当中是否包含字符(str.contain)
Jun 01 Python
pygame实现飞机大战
Mar 11 #Python
Django框架models使用group by详解
Mar 11 #Python
python检查目录文件权限并修改目录文件权限的操作
Mar 11 #Python
python 链接sqlserver 写接口实例
Mar 11 #Python
浅谈Python中range与Numpy中arange的比较
Mar 11 #Python
python读取当前目录下的CSV文件数据
Mar 11 #Python
python闭包、深浅拷贝、垃圾回收、with语句知识点汇总
Mar 11 #Python
You might like
使用 php4 加速 web 传输
2006/10/09 PHP
php实现的通用图片处理类
2015/03/24 PHP
php基于openssl的rsa加密解密示例
2016/07/11 PHP
DWZ+ThinkPHP开发时遇到的问题分析
2016/12/12 PHP
PHP实现基于面向对象的mysqli扩展库增删改查操作工具类
2017/07/18 PHP
php实现微信和支付宝支付的示例代码
2020/08/11 PHP
JQUERY 浏览器判断实现函数
2009/08/20 Javascript
JQuery 操作select标签实现代码
2010/05/14 Javascript
jquery复选框checkbox实现删除前判断
2014/04/20 Javascript
对new functionName()定义一个函数的理解
2014/05/22 Javascript
js实现的标题栏新消息闪烁提示效果
2014/06/06 Javascript
jQuery移动web开发中的页面初始化与加载事件
2015/12/03 Javascript
JavaScript中利用jQuery绑定事件的几种方式小结
2016/03/06 Javascript
纯JS打造网页中checkbox和radio的美化效果
2016/10/13 Javascript
利用CSS、JavaScript及Ajax实现图片预加载的方法
2016/11/29 Javascript
JavaScript运动框架 解决防抖动问题、悬浮对联(二)
2017/05/17 Javascript
ES6扩展运算符的用途实例详解
2017/08/20 Javascript
JavaScript中如何判断一个值的类型
2017/09/15 Javascript
基于Vue+element-ui 的Table二次封装的实现
2018/07/20 Javascript
使用validate.js实现表单数据提交前的验证方法
2018/09/04 Javascript
浅谈webpack性能榨汁机(打包速度优化)
2019/01/09 Javascript
JS 数组和对象的深拷贝操作示例
2020/06/06 Javascript
[03:24]2014DOTA2国际邀请赛 神秘商店生意火爆
2014/07/18 DOTA
[01:10:02]IG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python基于socket实现网络广播的方法
2015/04/29 Python
jupyter notebook引用from pyecharts.charts import Bar运行报错
2020/04/23 Python
html5的canvas实现3d雪花飘舞效果
2013/12/27 HTML / CSS
美国知名日用品连锁超市:Dollar General(多来店)
2017/01/14 全球购物
南非最大的花卉和送礼服务:NetFlorist
2017/09/13 全球购物
工程项目经理岗位职责
2013/12/15 职场文书
保护环境建议书300字
2014/05/13 职场文书
搭讪开场白台词大全
2015/05/28 职场文书
勇敢的心观后感
2015/06/09 职场文书
狼牙山五壮士观后感
2015/06/09 职场文书
货款欠条范本
2015/07/03 职场文书
漫画「请问您今天要来点兔子吗?」最新杂志彩页公开
2022/03/24 日漫