# 第二節:用戶對象
# 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