# 第二节:用户对象
# User模型
`User`模型是这个框架的核心部分。他的完整的路径是在`django.contrib.auth.models.User`。以下对这个`User`对象做一个简单了解:
## 字段:
内置的`User`模型拥有以下的字段:
1. `username`: 用户名。150个字符以内。可以包含数字和英文字符,以及`_`、`@`、`+`、`.`和`-`字符。不能为空,且必须唯一!
2. `first_name`:歪果仁的`first_name`,在30个字符以内。可以为空。
3. `last_name`:歪果仁的`last_name`,在150个字符以内。可以为空。
4. `email`:邮箱。可以为空。
5. `password`:密码。经过哈希过后的密码。
6. `groups`:分组。一个用户可以属于多个分组,一个分组可以拥有多个用户。`groups`这个字段是跟`Group`的一个多对多的关系。
7. `user_permissions`:权限。一个用户可以拥有多个权限,一个权限可以被多个用户所有用。和`Permission`属于一种多对多的关系。
8. `is_staff`:是否可以进入到`admin`的站点。代表是否是员工。
9. `is_active`:是否是可用的。对于一些想要删除账号的数据,我们设置这个值为`False`就可以了,而不是真正的从数据库中删除。
10. `is_superuser`:是否是超级管理员。如果是超级管理员,那么拥有整个网站的所有权限。
11. `last_login`:上次登录的时间。
12. `date_joined`:账号创建的时间。
## User模型的基本用法:
### 创建用户:
通过`create_user`方法可以快速的创建用户。这个方法必须要传递`username`、`email`、`password`。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.contrib.auth.models <span class="hljs-keyword">import</span> User
user = User.objects.create_user(<span class="hljs-string">'zhiliao'</span>,<span class="hljs-string">'hynever@zhiliao.com'</span>,<span class="hljs-string">'111111'</span>)
<span class="hljs-title"># 此时user对象已经存储到数据库中了。当然你还可以继续使用user对象进行一些修改</span>
user.last_name = <span class="hljs-string">'abc'</span>
user.save()
```
```
### 创建超级用户:
创建超级用户有两种方式。第一种是使用代码的方式。用代码创建超级用户跟创建普通用户非常的类似,只不过是使用`create_superuser`。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.contrib.auth.models <span class="hljs-keyword">import</span> User
User.objects.create_superuser(<span class="hljs-string">'admin'</span>,<span class="hljs-string">'admin@163.com'</span>,<span class="hljs-string">'111111'</span>)
```
```
也可以通过命令行的方式。命令如下:
```
<pre class="calibre12">```
python manage.py createsuperuser
```
```
后面就会提示你输入用户名、邮箱以及密码。
### 修改密码:
因为密码是需要经过加密后才能存储进去的。所以如果想要修改密码,不能直接修改`password`字段,而需要通过调用`set_password`来达到修改密码的目的。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.contrib.auth.models <span class="hljs-keyword">import</span> User
user = User.objects.get(pk=<span class="hljs-params">1</span>)
user.set_password(<span class="hljs-string">'新的密码'</span>)
user.save()
```
```
### 登录验证:
`Django`的验证系统已经帮我们实现了登录验证的功能。通过`django.contrib.auth.authenticate`即可实现。这个方法只能通过`username`和`password`来进行验证。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.contrib.auth <span class="hljs-keyword">import</span> authenticate
user = authenticate(username=<span class="hljs-string">'zhiliao'</span>, password=<span class="hljs-string">'111111'</span>)
<span class="hljs-title"># 如果验证通过了,那么就会返回一个user对象。</span>
<span class="hljs-keyword">if</span> user <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span>:
<span class="hljs-title"># 执行验证通过后的代码</span>
<span class="hljs-keyword">else</span>:
<span class="hljs-title"># 执行验证没有通过的代码。</span>
```
```
## 扩展用户模型:
`Django`内置的`User`模型虽然已经足够强大了。但是有时候还是不能满足我们的需求。比如在验证用户登录的时候,他用的是用户名作为验证,而我们有时候需要通过手机号码或者邮箱来进行验证。还有比如我们想要增加一些新的字段。那么这时候我们就需要扩展用户模型了。扩展用户模型有多种方式。这里我们来一一讨论下。
### 1. 设置Proxy模型:
如果你对`Django`提供的字段,以及验证的方法都比较满意,没有什么需要改的。但是只是需要在他原有的基础之上增加一些操作的方法。那么建议使用这种方式。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span><span class="hljs-params">(User)</span>:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
proxy = <span class="hljs-keyword">True</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_blacklist</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">return</span> self.objects.filter(is_active=<span class="hljs-keyword">False</span>)
```
```
在以上,我们定义了一个`Person`类,让他继承自`User`,并且在`Meta`中设置`proxy=True`,说明这个只是`User`的一个代理模型。他并不会影响原来`User`模型在数据库中表的结构。以后如果你想方便的获取所有黑名单的人,那么你就可以通过`Person.get_blacklist()`就可以获取到。并且`User.objects.all()`和`Person.objects.all()`其实是等价的。因为他们都是从`User`这个模型中获取所有的数据。
### 2. 一对一外键:
如果你对用户验证方法`authenticate`没有其他要求,就是使用`username`和`password`即可完成。但是想要在原来模型的基础之上添加新的字段,那么可以使用一对一外键的方式。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.contrib.auth.models <span class="hljs-keyword">import</span> User
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models
<span class="hljs-keyword">from</span> django.dispatch <span class="hljs-keyword">import</span> receiver
<span class="hljs-keyword">from</span> django.db.models.signals <span class="hljs-keyword">import</span> post_save
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserExtension</span><span class="hljs-params">(models.Model)</span>:</span>
user = models.OneToOneField(User,on_delete=models.CASCADE,related_name=<span class="hljs-string">'extension'</span>)
birthday = models.DateField(null=<span class="hljs-keyword">True</span>,blank=<span class="hljs-keyword">True</span>)
school = models.CharField(max_length=<span class="hljs-params">100</span>)
<span class="hljs-class">@receiver(post_save,sender=User)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_user_extension</span><span class="hljs-params">(sender,instance,created,**kwargs)</span>:</span>
<span class="hljs-keyword">if</span> created:
UserExtension.objects.create(user=instance)
<span class="hljs-keyword">else</span>:
instance.extension.save()
```
```
以上定义一个`UserExtension`的模型,并且让她和`User`模型进行一对一的绑定,以后我们新增的字段,就添加到`UserExtension`上。并且还写了一个接受保存模型的信号处理方法,只要是`User`调用了`save`方法,那么就会创建一个`UserExtension`和`User`进行绑定。
### 3. 继承自`AbstractUser`:
对于`authenticate`不满意,并且不想要修改原来`User`对象上的一些字段,但是想要增加一些字段,那么这时候可以直接继承自`django.contrib.auth.models.AbstractUser`,其实这个类也是`django.contrib.auth.models.User`的父类。比如我们想要在原来`User`模型的基础之上添加一个`telephone`和`school`字段。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.contrib.auth.models <span class="hljs-keyword">import</span> AbstractUser
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span><span class="hljs-params">(AbstractUser)</span>:</span>
telephone = models.CharField(max_length=<span class="hljs-params">11</span>,unique=<span class="hljs-keyword">True</span>)
school = models.CharField(max_length=<span class="hljs-params">100</span>)
<span class="hljs-title"># 指定telephone作为USERNAME_FIELD,以后使用authenticate</span>
<span class="hljs-title"># 函数验证的时候,就可以根据telephone来验证</span>
<span class="hljs-title"># 而不是原来的username</span>
USERNAME_FIELD = <span class="hljs-string">'telephone'</span>
REQUIRED_FIELDS = []
<span class="hljs-title"># 重新定义Manager对象,在创建user的时候使用telephone和</span>
<span class="hljs-title"># password,而不是使用username和password</span>
objects = UserManager()
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserManager</span><span class="hljs-params">(BaseUserManager)</span>:</span>
use_in_migrations = <span class="hljs-keyword">True</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_create_user</span><span class="hljs-params">(self,telephone,password,**extra_fields)</span>:</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> telephone:
<span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"请填入手机号码!"</span>)
user = self.model(telephone=telephone,*extra_fields)
user.set_password(password)
user.save()
<span class="hljs-keyword">return</span> user
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_user</span><span class="hljs-params">(self,telephone,password,**extra_fields)</span>:</span>
extra_fields.setdefault(<span class="hljs-string">'is_superuser'</span>,<span class="hljs-keyword">False</span>)
<span class="hljs-keyword">return</span> self._create_user(telephone,password)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_superuser</span><span class="hljs-params">(self,telephone,password,**extra_fields)</span>:</span>
extra_fields[<span class="hljs-string">'is_superuser'</span>] = <span class="hljs-keyword">True</span>
<span class="hljs-keyword">return</span> self._create_user(telephone,password)
```
```
然后再在`settings`中配置好`AUTH_USER_MODEL=youapp.User`。
**这种方式因为破坏了原来User模型的表结构,所以必须要在第一次**`migrate`**前就先定义好。**
### 4. 继承自`AbstractBaseUser`模型:
如果你想修改默认的验证方式,并且对于原来`User`模型上的一些字段不想要,那么可以自定义一个模型,然后继承自`AbstractBaseUser`,再添加你想要的字段。这种方式会比较麻烦,最好是确定自己对`Django`比较了解才推荐使用。步骤如下:
1. 创建模型。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span><span class="hljs-params">(AbstractBaseUser,PermissionsMixin)</span>:</span>
email = models.EmailField(unique=<span class="hljs-keyword">True</span>)
username = models.CharField(max_length=<span class="hljs-params">150</span>)
telephone = models.CharField(max_length=<span class="hljs-params">11</span>,unique=<span class="hljs-keyword">True</span>)
is_active = models.BooleanField(default=<span class="hljs-keyword">True</span>)
USERNAME_FIELD = <span class="hljs-string">'telephone'</span>
REQUIRED_FIELDS = []
objects = UserManager()
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_full_name</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">return</span> self.username
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_short_name</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">return</span> self.username
```
```
其中`password`和`last_login`是在`AbstractBaseUser`中已经添加好了的,我们直接继承就可以了。然后我们再添加我们想要的字段。比如`email`、`username`、`telephone`等。这样就可以实现自己想要的字段了。但是因为我们重写了`User`,所以应该尽可能的模拟`User`模型:
- `USERNAME_FIELD`:用来描述`User`模型名字字段的字符串,作为唯一的标识。如果没有修改,那么会使用`USERNAME`来作为唯一字段。
- `REQUIRED_FIELDS`:一个字段名列表,用于当通过`createsuperuser`管理命令创建一个用户时的提示。
- `is_active`:一个布尔值,用于标识用户当前是否可用。
- `get_full_name()`:获取完整的名字。
- `get_short_name()`:一个比较简短的用户名。
2. 重新定义`UserManager`:我们还需要定义自己的`UserManager`,因为默认的`UserManager`在创建用户的时候使用的是`username`和`password`,那么我们要替换成`telephone`。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserManager</span><span class="hljs-params">(BaseUserManager)</span>:</span>
use_in_migrations = <span class="hljs-keyword">True</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_create_user</span><span class="hljs-params">(self,telephone,password,**extra_fields)</span>:</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> telephone:
<span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"请填入手机号码!"</span>)
user = self.model(telephone=telephone,*extra_fields)
user.set_password(password)
user.save()
<span class="hljs-keyword">return</span> user
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_user</span><span class="hljs-params">(self,telephone,password,**extra_fields)</span>:</span>
extra_fields.setdefault(<span class="hljs-string">'is_superuser'</span>,<span class="hljs-keyword">False</span>)
<span class="hljs-keyword">return</span> self._create_user(telephone,password)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_superuser</span><span class="hljs-params">(self,telephone,password,**extra_fields)</span>:</span>
extra_fields[<span class="hljs-string">'is_superuser'</span>] = <span class="hljs-keyword">True</span>
<span class="hljs-keyword">return</span> self._create_user(telephone,password)
```
```
3. 在创建了新的`User`模型后,还需要在`settings`中配置好。配置`AUTH_USER_MODEL='appname.User'`。
4. 如何使用这个自定义的模型:比如以后我们有一个`Article`模型,需要通过外键引用这个`User`模型,那么可以通过以下两种方式引用。
第一种就是直接将`User`导入到当前文件中。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models
<span class="hljs-keyword">from</span> myauth.models <span class="hljs-keyword">import</span> User
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span>
title = models.CharField(max_length=<span class="hljs-params">100</span>)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
```
```
这种方式是可以行得通的。但是为了更好的使用性,建议还是将`User`抽象出来,使用`settings.AUTH_USER_MODEL`来表示。示例代码如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models
<span class="hljs-keyword">from</span> django.conf <span class="hljs-keyword">import</span> settings
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span>
title = models.CharField(max_length=<span class="hljs-params">100</span>)
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
```
```
**这种方式因为破坏了原来User模型的表结构,所以必须要在第一次**`migrate`**前就先定义好。**
- Introduction
- 第一章:学前准备
- 第一节:虚拟环境
- 第二节:准备工作
- 第三节:Django介绍
- 第四节:URL组成部分
- 第二章:URL与视图
- 第一节:第一个Django项目
- 第二节:视图与URL分发器
- 第三章:模板
- 第一节:模板介绍
- 第二节:模板变量
- 第三节:常用标签
- 第四节:常用过滤器
- 第五节:自定义过滤器
- 第七节:模版结构优化
- 第八节:加载静态文件
- 第四章:数据库
- 第一节:MySQL相关软件
- 第二节:数据库操作
- 第三节:ORM模型
- 第四节:模型常用字段
- 第五节:外键和表关系
- 第六节:增删改查操作
- 第七节:查询操作
- 第八节:QuerySet API
- 第九节:ORM模型迁移
- 第十节:ORM作业
- 第十一节:ORM作业参考答案
- 第十二节:Pycharm连接数据库
- 第五章:视图高级
- 第一节:限制请求method
- 第二节:页面重定向
- 第三节:HttpRequest对象
- 第四节:HttpResponse对象
- 第五节:生成CSV文件
- 第六节:类视图
- 第七节:错误处理
- 第六章:表单
- 第一节:表单概述
- 第二节:用表单验证数据
- 第三节:ModelForm
- 第四节:文件上传
- 第七章:cookie和session
- 第八章:上下文处理器和中间件
- 第一节:上下文处理器
- 第二节:中间件
- 第九章:安全
- 第一节:CSRF攻击
- 第二节:XSS攻击
- 第三节:点击劫持攻击
- 第四节:SQL注入
- 第十章:信号
- 第一节:什么是信号
- 第十一章:验证和授权
- 第一节:概述
- 第二节:用户对象
- 第三节:权限和分组
- 第十二章:Admin系统
- 第十三章:Django的缓存
- 第十四章:memcached
- 第十五章:Redis