1. 程式人生 > >django框架之auth模塊

django框架之auth模塊

obj 不一致 用戶登錄 回顧 title abstract null valid exce

內容回顧
1. form表單組件
1. 常用字段
1. CharField()
2. ChoiceField()
2. 參數或配置
1. label="label標簽顯示的文本內容"
2. initial="默認值"
3. widget=forms.widgets.TextInput() --> <input typle=‘text‘/>
widget=forms.widgets.PasswordInput(
attrs={"class": "c1", "s12": "hao"}
)
4. required=False --> is_valid()校驗的時候該字段沒有值也不報錯
5. error_messages={"required": "xx字段不能為空", "max_length": "xx字段最多不能超過位數"}
6. max_length
7. min_length

8. validators=[驗證器1,驗證器2, ...]
3. 驗證器
1. 內置正則驗證
from django.core.validators import RegexValidator
validators=[RegexValidator(r‘^1[3-9]\d{9}$‘, "手機號碼格式不正確!"), ]
2. 自定義方法實現
from django.core.exceptions import ValidationError
# 自定義校驗的方法
def name_check(value):
if ‘西遊記‘ in value:
raise ValidationError("不符合社會主義核心價值觀!")
else:
return value

validators=[name_check, ],
4. 鉤子函數
0. self.cleaned_data --> 用來存放經過驗證數據的大字典
self.add_error("字段名", "錯誤提示信息")

1. 局部鉤子(Hook)
通過自定義一個clean_字段名的方法實現字段的校驗
2. 全局鉤子
此時 每個字段獨立的校驗都走完了,cleaned_data中已經存放著所有字段的數據
def clean(self):
print("我可是看過源碼的人,我知道你肯定會執行這個方法!")
# 重寫父類的clean方法
# 該clean方法, 在每個字段都校驗通過之後才調用執行
pwd = self.cleaned_data.get("pwd")
re_pwd = self.cleaned_data.get("re_pwd")

if re_pwd and re_pwd == pwd:
# 確認密碼和密碼相同, 正常
return self.cleaned_data
else:
# 確認密碼和密碼不同
self.add_error(‘re_pwd‘, "兩次密碼不一致") # ?
raise ValidationError("兩次密碼不一致")

今日內容:

Django自帶的用戶認證:

我們在開發一個網站的時候,無可避免的需要設計實現網站的用戶系統。此時我們需要實現包括用戶註冊、用戶登錄、用戶認證、註銷、修改密碼等功能,這還真是個麻煩的事情呢。

Django作為一個完美主義者的終極框架,當然也會想到用戶的這些痛點。它內置了強大的用戶認證系統--auth,它默認使用 auth_user 表來存儲用戶數據。

auth模塊:

首先執行數據庫遷移的兩條命令,然後再數據庫中會有這樣一個表,author_user,這是django自帶的一個用戶表。

通過django創建超級用戶:

python manage.py createsuperuser

authenticate() :

提供了用戶認證功能,即驗證用戶名以及密碼是否正確,一般需要username 、password兩個關鍵字參數。

如果認證成功(用戶名和密碼正確有效),便會返回一個 User 對象。

authenticate()會在該 User 對象上設置一個屬性來標識後端已經認證了該用戶,且該信息在後續的登錄過程中是需要的。

用法:

login(HttpRequest, user)

該函數接受一個HttpRequest對象,以及一個經過認證的User對象。

該函數實現一個用戶登錄的功能。它本質上會在後端為該用戶生成相關session數據。

我們寫一個登陸認證的例子:

我們在認證的時候,因為author_user是django自帶的表,所以我們沒辦法用 models.類名 去數據庫裏面查詢username和password,這時候就要:

from django.contrib import auth

def login(request):
err_msg = ‘‘
if request.method == ‘POST‘:
username = request.POST.get(‘username‘)
password = request.POST.get(‘pwd‘)
# username 和password 都匹配成功就返回一個user對象.
user = auth.authenticate(username=username, password=password)
if user:
#用戶名 密碼正確
# 1 讓當前用戶登錄,給session和cookie寫入數據
auth.login(request,user)
return redirect(request,‘index.html’)
else:
#用戶名或密碼錯誤
err_msg = ‘用戶名或密碼錯誤‘
return render(request,‘login.html‘,{‘err_msg‘:err_msg})


logout(request) :

該函數接受一個HttpRequest對象,無返回值。

當調用該函數時,當前請求的session信息會全

def logout(request):
    #註銷
    auth.logout(request)
    return redirect(/login/)

這樣就清楚了session數據。

login_requierd()

現在如果我們直接輸入index頁面的網址,也是可以直接訪問的。這顯然不是我們想要的,我們需要先登陸然後再進入index頁面。

auth 給我們提供的一個裝飾器工具,用來快捷的給某個視圖添加登錄校驗。

from django.contrib.auth.decorators import login_required

@login_required
def index(request):
    return render(request,index.html)

若用戶沒有登錄,則會跳轉到django默認的 登錄URL ‘/accounts/login/ ‘ 並傳遞當前訪問url的絕對路徑 (登陸成功後,會重定向到該路徑)。

如果需要自定義登錄的URL,則需要在settings.py文件中通過LOGIN_URL進行修改。

LOGIN_URL = /login/  # 這裏配置成你項目登錄頁面的路由

is_authenticated():

用來判斷當前請求是否通過了認證。

def index(request):
    #用來判斷當前請求是否通過了認證。
    print(request.user,request.user.is_authenticated())
    return render(request,index.html)

現在我們寫一個註冊,利用之前學過的form表單,讓用戶去填寫,然後拿用戶的信息在試圖的函數中認證登陸。

創建一個forms文件夾:

from django import forms


class RegForm(forms.Form):
    username = forms.CharField(
        label=用戶名,
    )
    password = forms.CharField(
        label=密碼,
        widget = forms.widgets.PasswordInput()
    )
    re_password = forms.CharField(
        label=確認密碼,
        widget = forms.widgets.PasswordInput()
    )

views.py代碼:

from app01 import forms


def register(request):
    form_obj = forms.RegForm()
    if request.method == POST:
        from_obj = forms.RegForm(request.POST)
      。。。
    return render(request,register.html,{form_obj:form_obj})

html代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊</title>
</head>
<body>
<form action="/register/">
    {% csrf_token %}
{#    {{ form_obj.as_p }}#}
    <div>
        <label for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
        {{ form_obj.username }}
    </div>
    <div>
        <label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
        {{ form_obj.password }}
    </div>
    <div>
        <label for="{{ form_obj.re_password.id_for_label }}">{{ form_obj.re_password.label }}</label>
        {{ form_obj.re_password }}
    </div>
    <input type="button" value="註冊">
</form>
</body>
</html>

由於這是django自己的表,所以不能像之前用我們自己的表的創建方法去創建用戶,這裏提供了:

create_user():

auth 提供的一個創建新用戶的方法,需要提供必要參數(username、password)等。

def register(request):
    form_obj = RegForm()
    if request.method == POST:
        form_obj = RegForm(request.POST)
        if form_obj.is_valid():
            print(form_obj.cleaned_data)#打印form表單中經過驗證的數據 cleaned_data中多了re_password字段。
            # 吧re_pqssword字段從cleaned_data移除
            form_obj.cleaned_data.pop(re_password)
            User.objects.create_user(**form_obj.cleaned_data)
            return  HttpResponse(ok)
    return render(request,register.html,{form_obj:form_obj})

create_superuser():

auth 提供的一個創建新的超級用戶的方法,需要提供必要參數(username、password)等。

方法和創建普通用戶的方法相同

check_password(password):

auth 提供的一個檢查密碼是否正確的方法,需要提供當前請求用戶的密碼。

密碼正確返回True,否則返回False。



ok = user.check_password(‘舊密碼)     #user就是當前登陸的user   request.user

set_password(password):

auth 提供的一個修改密碼的方法,接收 要設置的新密碼 作為參數。

註意:設置完一定要調用用戶對象的save方法!!!



user.set_password(‘新密碼’)
user.save()

一個修改密碼功能的簡單示例:

views.py代碼:

def setpassword(request):
    err_msg = ‘‘
    if request.method == POST:
        # print(request.user)
        # print(request.user.password)
        # print(request.user.username)
        user = request.user
        old_password = request.POST.get(old_password)
        new_password = request.POST.get(new_password)
        print(old_password, new_password)
        if user.check_password(old_password):
            user.set_password(new_password)
            user.save()
            return redirect(/login/)
        else:
            err_msg = 原密碼輸入有誤
    return render(request,setpassword.html,{err_msg: err_msg})

html代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改密碼</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <div>
        <label for="old_password">原密碼:</label>
        <input type="text" name="old_password">
    </div>
    <div>
        <label for="new_password">新密碼:</label>
        <input type="password" name="new_password">
    </div>
    <input type="submit" value="提交">
    <span>{{ err_msg }}</span>
</form>
</body>
</html>

現在我們想要在auth_user表上添加一個字段怎麽辦?

擴展默認的auth_user表:

from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
    """
    用戶信息表
    """
    phone = models.CharField(max_length=11, null=True, unique=True)

註意:

按上面的方式擴展了內置的auth_user表之後,一定要在settings.py中告訴Django,我現在使用我新定義的UserInfo表來做用戶認證。寫法如下:

# 引用Django自帶的User表,繼承使用時需要設置
AUTH_USER_MODEL = "app名.UserInfo"

再次註意:

一旦我們指定了新的認證系統所使用的表,我們就需要重新在數據庫中創建該表,而不能繼續使用原來默認的auth_user表了。

django框架之auth模塊