一、Auth 模塊是什麼 Auth 模塊是Django中自帶的用戶認證模塊。 一個網站系統需要實現用戶註冊、用戶登錄、用戶認證、註銷、修改密碼等功能,Django中內置了強大的認證系統-auth,預設使用 auth_user 表來存儲用戶的數據。 同時Django有一個後臺管理系統(127.0.0. ...
一、Auth 模塊是什麼
Auth 模塊是Django中自帶的用戶認證模塊。
一個網站系統需要實現用戶註冊、用戶登錄、用戶認證、註銷、修改密碼等功能,Django中內置了強大的認證系統-auth,預設使用 auth_user 表來存儲用戶的數據。
同時Django有一個後臺管理系統(127.0.0.1:8000/admin),使用的用戶名和密碼也是這張數據表中的數據。
預設後臺管理的用戶名和密碼是沒有的,需要我們創建一個出來,而且只有超級管理員才能登錄這個頁面,那我們現在就來創建這樣一個超級用戶。
二、擴展預設的 auth_user 表
在一個新的項目中,先設計項目的資料庫,表關係,Django 系統內置的認證系統(auth_user表)很好用,但是表欄位都是固定的幾個,無法進行對它擴展。
比如,預設欄位不夠我們使用,我們可以對其進行拓展,存儲用戶手機號、時間等欄位,設置表和表之間關係,怎麼辦?
現在就來設計擴展一下這個表,需要兩步
1 配置settings
在 settings.py 配置文件中增加一句話,告訴Django 使用新定義的 UserInfo 表來做用戶認證的表。
# settings.py
# 聲明使用自定義表作為用戶驗證,聲明格式為: 應用名.表名,繼承使用時需要設置
AUTH_USER_MODEL = 'app.UserInfo'
2 配置models
創建一個自定義類並繼承AbstractUser類,然後編寫 AbstractUser 類中沒有的欄位並且'不能衝突'。
# app/models.py
from django.db import models
# 導入AbstractBaseUser類,繼承AbstractBaseUser類,基本欄位
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
'''
擴展用戶信息表
繼承原有的auth_user表欄位
'''
nid = models.AutoField(primary_key = True)
phone = models.CharField(max_length = 11, blank = True, null = True, unique = True, verbose_name = "手機號")
avatar = models.FileField(upload_to = "avatar", default = "avatar/default.png")
create_time = models.DateField(auto_now_add = True)
blog = models.OneToOneField(to = 'Blog', null = True, to_field = 'bid', on_delete = models.CASCADE)
class Meta:
verbose_name_plural = '用戶表'
def __str__(self):
return self.username
class Blog(models.Model):
bid = models.AutoField(primary_key = True)
site_name = models.CharField(verbose_name = "站點名稱", max_length = 32)
site_title = models.CharField(verbose_name = "站點標題", max_length = 32)
site_theme = models.CharField(verbose_name = "站點樣式", max_length = 255)
def __str__(self):
return self.site_name
最後,執行兩條資料庫遷移命令。
python manage.py makemigrations
python manage.py migrate
註意:所在的庫必須是第一次執行遷移命令才可以,若是原本有殘留會 引起異常。
三、創建超級用戶
預設後臺管理的用戶名和密碼是沒有的,需要我們創建一個出來,而且只有超級管理員才能登錄這個頁面,那我們現在就來創建這樣一個超級用戶
python manage.py createsuperuser
四、Auth 模塊常用方法
1 auth模塊常用方法
from django.contrib import auth
2 authenticate()
校驗用戶名和密碼是否正確,可以用來判斷當前是否登錄,也就是否有session數據。
from django.shortcuts import render, HttpResponse, redirect
from django.contrib import auth
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user_obj = auth.authenticate(request, username=username, password=password)
print(user_obj)
if user_obj:
# 保存用戶狀態
auth.login(request, user_obj)
return HttpResponse('OK')
return render(request, 'login.html')
authenticate方法如果認證成功(用戶名和密碼正確有效,就是去 UserInfo 表中查詢一下是否存在這條記錄),便會返回一個 User 對象,查詢認證失敗返回None。
templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>username:<input type="text" name="username"></p>
<p>password:<input type="text" name="password"></p>
<input type="submit">
</form>
</body>
</html>
3 login(HttpRequest, user)
該函數接受一個 HttpRequest 對象,以及一個經過認證的 User 對象。
可以在驗證成功後進行登錄,它本質上會在後端為該用戶生成相關session數據。
# 保存用戶狀態,相當於設置 session 值。
# 只要執行了此操作,後面的視圖函數只要能夠拿到request就可以通過 request.user 獲取到當前的用戶對象。
auth.login(request, user_obj)
4 logout(request)
該函數接受一個HttpRequest對象,無返回值。註銷。
當調用該函數時,當前請求的session信息會全部清除。該用戶即使沒有登錄,使用該函數也不會報錯。
def logout(request):
# 類似於request.session.flush()
auth.logout(request)
return redirect('/login/')
5 is_authenticated()
用來判斷當前請求是否通過了認證。
def home(request):
print(request.user) # 用戶對象 AnonymousUser匿名用戶
print(request.user.is_authenticated())
if not request.user.is_authenticated():
return redirect('/home/')
return redirect('/register/')
6 login_requierd()
校驗用戶是否登錄的裝飾器。
判斷當前用戶是否登錄那種方式很複雜,需要再每個功能函數中寫上這麼一段,那麼auth模塊也幫我們提供了一個現成的登錄認證裝飾器。
from django.contrib.auth.decorators import login_required
# auth 模塊提供的登錄裝飾器提供兩個配置: 局部配置和全局配置
# 局部配置
@login_required(login_url='/login/') # 用戶沒有登錄會跳到login頁面
def home(request):
# if not request.user.is_authenticated:
# return redirect('/login/')
return HttpResponse('歡迎來到home頁面')
# 全局配置:
# settings.py配置文件中配置
LOGIN_URL = '/login/'
# 如果全局配置和局部配置都設置了,那麼會以局部配置優先。
7 create_superuser()
auth 提供的一個創建新普通用戶/超級管理員用戶的方法,需要提供必要參數(username、password)等。
from app import models
# 操作auth_user表寫入數據
def register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 寫入數據不能用create密碼沒有加密處理
# models.UserInfo.objects.create(username=username, password=password)
# 創建普通用戶
# models.UserInfo.objects.create_user(username=username, password=password)
# 創建超級用戶(瞭解):使用代碼創建超級用戶 郵箱是必填的 而用命令創建則可以不填
models.UserInfo.objects.create_superuser(username=username, password=password, email='[email protected]')
return render(request, 'register.html')
templates/register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Register</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>username:<input type="text" name="username"></p>
<p>password:<input type="text" name="password"></p>
<input type="submit">
</form>
</body>
</html>
8 check_password()
auth 提供的一個檢查密碼是否正確的方法,需要提供當前請求用戶的密碼。
密碼正確返回True,否則返回False。
9 set_password
auth 提供的一個修改密碼的方法,接收新密碼作為參數,校驗原密碼並修改密碼。
def set_password(request):
if request.method == 'POST':
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('confirm_password')
# 先校驗兩次密碼是否一致
if new_password == confirm_password:
# 校驗老密碼對不對
is_right = request.user.check_password(old_password)
if is_right:
# 修改密碼
request.user.set_password(new_password) # 僅僅是在修改對象的屬性
request.user.save() # 將修改操作保存到資料庫
return redirect('/login/')
return render(request, 'set_password.html', locals())
templates/set_password.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>密碼修改</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>username:<input type="text" name="username" disabled value="{{ request.user.username }}"></p>
<p>old_password:<input type="text" name="old_password"></p>
<p>new_password:<input type="text" name="new_password"></p>
<p>confirm_password:<input type="text" name="confirm_password"></p>
<input type="submit">
</form>
</body>
</html>
五、後臺管理系統配置
1 在該表對應的models類裡面添加一個Meta類
class Meta:
verbose_name_plural = '用戶表' #指定該表在admin後臺的名字為:用戶表
2 null=True,blank=True的區別
# null=True: 是告訴資料庫該欄位可以為空,admin後臺預設還是不允許為空
# blank=True: admin 後臺該欄位可以為空
phone = models.CharField(max_length = 11, blank = True, null = True, unique = True, verbose_name = "手機號")
3 settings.py配置,使django的後臺管理頁面變成中文、設置時區
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
六、ModelAdmin的常用屬性
1 註冊表
在admin.py中只需要 Mode 中的某個類註冊,即可在 Admin 中實現增刪改查的功能。
from django.contrib import admin
from app import models
# Register your models here.
admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
註冊完的結果如下圖所示,點擊表名即可修改表內容。
2 list_display欄位展示
- list_display:列表時,定製顯示的列。
- 在預設的情況下,Model 在 admin 列表修改頁(Admin ChangeList)只會顯示一列,內容是實例對象的__str__的返回值,如果想要多現實一些列的數據,就可以通過 list_display 屬性來實現。
- 它除了可以配置 Model 的欄位名之外,還可以接收函數,且這個函數將一個 Model 實例對象作為參數,這個函數也需定義在 ModeAdmin 中。語法格式如下:list_display=[]
- 在使用 list_display 時需要特別註意它的兩個特性
- 對於 Foreignkey 類型的欄位,顯示的是 obj.__str__() 返回的值。
- 不支持 ManyToManyField 類型的欄位,如果需要展示,可以用自定義方法實現。
# 方式一
class UserInfoAdmin(admin.ModelAdmin):
list_display = ('username', 'email',)
admin.site.register(models.UserInfo, UserInfoAdmin) # 第一個參數可以是列表
# 方式二
@admin.register(models.UserInfo) # 第一個參數可以是列表
class UserInfoAdmin(admin.ModelAdmin):
list_display = ('username', 'email',)
3 list_display_links,列表時,定製列可以點擊跳轉。
4 list_filter
- 配置 list_filter 屬性,可以在 Admin 後臺的列表修改頁的右側添加過濾器,且各個過濾條件是 and 的關係。
- list_filter 是列表或者元組類型,通常使用它會傳遞兩類元素:一個是 Model 的欄位名,另一個是繼承自以下的類(並不常用):django.contrib.admin.SimpleListFilter
- 對於 Model 的欄位名,欄位類型必須屬於 BooleanField、CharField、DateField、DateTimeField、IntegerField、ForeignKey 或 ManyToManyField 中的一種。同樣也可以使用雙下畫線實現跨表關聯。示例如下所示:list_filter= ['title', 'pub__pubname']
5 list_editable,列表時,可以編輯的列 。
cclass UserInfoAdmin(admin.ModelAdmin):
list_display = ('email', 'create_time', 'phone',)
list_display_links = ( 'create_time',)
list_filter = ('email', 'phone',)
list_editable = ('email', )
admin.site.register(models.UserInfo, UserInfoAdmin)
5 list_select_related,列表時,連表查詢是否自動 select_related