在開發過程中,模型User的字段可能滿足不了複雜的開發需求。現在大多數網站的用戶信息都有用戶的手機號碼、QQ號碼和微信號們等一系列個人信息。爲了滿足各種需求,Django提供了三種模型擴展的方法:
1、代理模型:這是一種模型繼承,這種模型在數據庫中無須創建新數據表。一般用於改變現有模型的行爲方式,如增加新方法函數等,並且不影響現有數據庫的結構。當不需要在數據庫中存儲額外的信息,而需要增加操作方式或更改模型的查詢管理方式,適合使用代理模型來擴展現有User模型。
2、Profile擴展模型User:當存儲的信息與模型User相關,而且並不改變模型User原有的認證方法時,可定義新的模型MyUser,並設置某個字段爲OneToOneField,這樣能與模型User形成一對一關聯,該方法稱爲用戶配置(User Profile)。
3、AbstractUser擴展模型User:如果模型User內置的方法符合開發需求,在不改變這些函數方法的情況下,添加模型User的額外字段,可通過AbstractUser方式實現。使用AbstractUser定義的模型會替換原有模型User。
上述三種方法各有優缺點,一般情況下,建議使用AbstractUser擴展模型User,因爲該方式對原有模型User影響較少而且無須額外創建數據表。下面以MyDjango項目爲例講解如何使用AbstractUser擴展模型User。首先在MySQL中找到項目所使用的數據庫,並清除數據庫中全部的數據表,注意了刪除數據庫一定要小心,我這邊之前刪除了數據庫之後怎麼也創建不了了花費了我半天才搞定,因爲我app之前設置了很多關聯的東西所以要把之前那些關聯的東西都註銷掉再創建,這裏我就把我之前那個index的models.py以及關聯的文件都註銷掉在user的models.py文件中定義模型MyUser,代碼如下:
#user/models.py
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
qq = models.CharField('QQ號碼', max_length=16)
weChat = models.CharField('微信賬號', max_length=100)
mobile = models.CharField('手機號碼', max_length=11)
#設置返回值
def __str__(self):
return self.username
模型MyUser繼承自AbstractUser類,AbstractUser類已有內置模型User的字段屬性,因此模型MyUser具有模型User的全部屬性。在執行數據遷移(創建數據表)之前,必須要在項目的settings.py中配置相關信息,配置信息如下:
#settings.py
AUTH_USER_MODEL = 'user.MyUser'
配置信息是將內置模型User替換成user定義的模型MyUser,若沒有設置配置信息,在創建數據表的時候,會分別創建數據表auth_user和user_myuser。在PyCharm的Terminal下執行數據遷移:
python manage.py makemigrations
python manage.py migrate
打開數據庫查看數據表信息,可以發現內置模型User的數據表auth_user改爲數據表user_myuser,並且數據表user_myuser的字段除了具有內置模型User的字段之外,還額外增加了自定義的字段。
上述例子使用AbstractUser擴展模型User,實現過程可分爲兩個步驟:
1、定義新的模型MyUser,該模型必須繼承AbstractUser類,在模型MyUser下定義的字段爲擴展字段。
2、在項目的配置文件settings.py中配置AUTH_USER_MODEL信息,在數據遷移時,將內置模型User替換成user定義的模型MyUser。
完成模型User的擴展後,接着探討模型MyUser與內置模型User在實際開發過程中是否存在使用上的差異。首先是要python manage.py createsuperuser創建超級用戶並登錄Admin後臺管理系統:
認證與授權沒有用戶信息表,因爲模型MyUser是在user的models.py中定義的。若將模型MyUser展示在後臺系統,則可以在user的admin.py中定義相關數據對象:
在user的admin裏面添加代碼:
from django.contrib import admin
from .models import MyUser
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
# Register your models here.
@admin.register(MyUser)
class MyUserAdmin(UserAdmin):
list_display = ['username', 'email', 'mobile', 'qq', 'weChat']
# 修改用戶時,在個人信息裏添加'mobile'、'qq'、'weChat'的信息錄入
# 將源碼的UserAdmin.fieldsets轉換成列表格式
fieldsets = list(UserAdmin.fieldsets)
# 重寫UserAdmin的fieldsets,添加'mobile'、'qq'、'weChat'的信息錄入
fieldsets[1] = (_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'mobile', 'qq', 'weChat')})
user下的_init_.py添加代碼:
#設置App(user)的中文名
from django.apps import AppConfig
import os
#修改app在admin後臺顯示名稱
#default_app_config的值來自apps.py的類名
default_app_config = 'user.IndexConfig'
#獲取當前app的命名
def get_current_app_name(_file):
return os.path.split(os.path.dirname(_file))[-1]
#重寫類IndexConfig
class IndexConfig(AppConfig):
name = get_current_app_name(__file__)
verbose_name = '用戶管理'
刷新瀏覽器看看效果
上面例子中,admin.py定義的MyUserAdmin繼承自UserAdmin,UserAdmin是內置模型User的Admin數據對象,源碼可在Python安裝目錄Lib\site-packages\django\contrib\auth\admin.py中查看。因此,在定義MyUserAdmin時,直接繼承UserAdmin,並通過重寫某些屬性,可以快速開發擴展模型MyUser的Admin後臺數據對象。
除了繼承UserAdmin的Admin數據對象之外,還可以在表單中繼承內置模型User所定義的表單類。內置表單類可以在Python安裝目錄Lib\site-packages\django\contrib\auth\forms.py下查看源碼。從源碼中發現,forms.py定義了多個內置表單類,如圖表:
從上述內置的表單類可以發現,這些表單類都涉及模型User的字段,說明這些表單都是在內置模型User的基礎上實現的。因此,我們爲擴展模型MyUser定義相關的表單類可以繼承上述的表單類。以UserCreationForm爲例,使用表單類UserCreationForm實現用戶註冊功能。在user中創建form.py文件來重寫表單類:
from django.contrib.auth.forms import UserCreationForm
from .models import MyUser
class MyUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = MyUser
#在註冊界面添加郵箱、手機號碼、微信號碼和QQ號碼
fields = UserCreationForm.Meta.fields + ('email', 'mobile', 'weChat', 'qq')
自定義表單類MyUserCreationForm繼承自表單類UserCreationForm,並且重寫類Meta的屬性model和屬性fields,分別重新設置表單類所綁定的模型和字段。然後在模板user.html和視圖函數regusterView中編寫一下代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
<div class="container">
<div class="flex-center">
<div class="unit-1-2 unit-1-on-mobile">
<h1>MyDjango Auth</h1>
{% if tips %}
<div>{{ tips }}</div>
{% endif %}
<form class="form" action="" method="post">
{% csrf_token %}
<div>用戶名:{{ user.username }}</div>
<div>郵 箱:{{ user.email }}</div>
<div>手機號:{{ user.mobile }}</div>
<div>Q Q 號:{{ user.qq }}</div>
<div>微信號:{{ user.weChat }}</div>
<div>密 碼:{{ user.password1 }}</div>
<div>密碼確認:{{ user.password2 }}</div>
<button type="submit" class="btn btn-primary btn-block">注 冊</button>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
#使用表單實現用戶註冊
def registerView(request):
if request.method == 'POST':
user = MyUserCreationForm(request.POST)
if user.is_valid():
user.save()
tips = '註冊成功'
user = MyUserCreationForm()
else:
user = MyUserCreationForm()
return render(request, 'user.html', locals())
從上述代碼可以看到,視圖函數registerView使用表單類MyUserCreationForm實現用戶註冊功能,功能說明如下:
1、當用戶在瀏覽器上訪問http://127.0.0.1:8000/user/register.html時,視圖函數首先將表單類MyUserCreationForm實例化後傳給模板,在網頁上生成用戶註冊的表單界面。
2、輸入用戶信息並單擊"註冊"按鈕,程序將表單數據交給表單類MyUserCreationForm處理並生成user對象。
3、最後驗證user對象的數據格式,若驗證成功通過,則將數據保存到數據表user_myuser中
本文參考:Auth認證系統