作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!
之前了解了:
- 創建Django項目
- 數據庫
- 模板
- 表格提交
- admin管理頁面
上面的功能模塊允許我們做出一個具有互動性的站點,但無法驗證用戶的身份。我們這次了解用戶驗證部分。通過用戶驗證,我們可以根據用戶的身份,提供不同的服務。
一個Web應用的用戶驗證是它的基本組成部分。我們在使用一個應用時,總是從“登錄”開始,到“登出”結束。另一方面,用戶驗證又和網站安全、數據庫安全息息相關。HTTP協議是無狀態的,但我們可以利用儲存在客戶端的cookie或者儲存在服務器的session來記錄用戶的訪問。
Django有管理用戶的模塊,即django.contrib.auth。你可以在mysite/settings.py里看到,這個功能模塊已經注冊在INSTALLED_APPS中。利用該模塊,你可以直接在邏輯層面管理用戶,不需要為用戶建立模型,也不需要手工去實現會話。
“為了救你的愛人出來,我們要演一場戲。”
創建用戶
你可以在admin頁面直接看到用戶管理的對話框,即Users。從這里,你可以在這里創建、刪除和修改用戶。點擊Add增加用戶daddy,密碼為daddyiscool。
在admin頁面下,我們還可以控制不同用戶組對數據庫的訪問權限。我們可以在Groups中增加用戶組,設置用戶組對數據庫的訪問權限,並將用戶加入到某個用戶組中。
在這一章節中,我們創立一個新的app,即users。下文的模板和views.py,都針對該app。
"你這套新衣服,還真像那么回事",德國人說。
用戶登錄
我們建立一個簡單的表格。用戶通過該表格來提交登陸信息,並在Django服務器上驗證。如果用戶名和密碼正確,那么登入用戶。
我們首先增加一個登錄表格:
<form role="form" action="/login" method="post">
<label>Username</label>
<input type="text" name='username'>
<label>Password</label>
<input name="password" type="password">
<input type="submit" value="Submit">
</form>
我們在views.py中,定義處理函數user_login(),來登入用戶:
# -*- coding: utf-8 -*-
from django.shortcuts import render, redirect from django.core.context_processors import csrf from django.contrib.auth import *
def user_login(request): ''' login '''
if request.POST: username = password = '' username = request.POST.get('username') password = request.POST.get('password') user = authenticate(username=username, password=password) if user is not None and user.is_active: login(request, user) return redirect('/') ctx = {} ctx.update(csrf(request)) return render(request, 'login.html',ctx)
上面的authenticate()函數,可以根據用戶名和密碼,驗證用戶信息。而login()函數則將用戶登入。它們來自於django.contrib.auth。
作為替換,我們可以使用特別的form對象,而不自行定義表格。這將讓代碼更簡單,而且提供一定的完整性檢驗。
練習. 使用contrib.auth.forms.AuthenticationForm。來簡化上面的模板和處理函數。
德國人還是不忘一再叮囑,"記住,我們可不是什么賞金獵人。"
登出
有時用戶希望能銷毀會話。我們可以提供一個登出的URL,即/users/logout。登入用戶訪問該URL,即可登出。在views.py中,增加該URL的處理函數:
# -*- coding: utf-8 -*-
from django.shortcuts import redirect def user_logout(request): ''' logout URL: /users/logout ''' logout(request) return redirect('/')
我們修改urls.py,讓url對應user_logout()。訪問http://127.0.0.1/users/logout,就可以登出用戶。
德國人壓低聲音,“哦,我是來救你的,我們要演一出戲。”
views.py中的用戶
上面說明了如何登入和登出用戶,但還沒有真正開始享受用戶驗證帶來的好處。用戶登陸的最終目的,就是為了讓服務器可以區別對待不同的用戶。比如說,有些內容只能讓登陸用戶看到,有些內容則只能讓特定登陸用戶看到。我們下面將探索如何實現這些效果。
在Django中,對用戶身份的檢驗,主要是在views.py中進行。views.py是連接模型和視圖的中間層。HTTP請求會轉給views.py中的對應處理函數處理,並發回回復。在views.py的某個處理函數准備HTTP回復的過程中,我們可以檢驗用戶是否登陸。根據用戶是否登陸,我們可以給出不同的回復。最原始的方式,是使用if式的選擇結構:
# -*- coding: utf-8 -*-
from django.http import HttpResponse def diff_response(request): if request.user.is_authenticated(): content = "<p>my dear user</p>"
else: content = "<p>you wired stranger</p>"
return HttpResponse(content)
可以看到,用戶的登錄信息包含在request.user中,is_authenticated()方法用於判斷用戶是否登錄,如果用戶沒有登錄,那么該方法將返回false。該user對象屬於contrib.auth.user類型,還有其它屬性可供使用,比如
屬性 | 功能 |
get_username() | 返回用戶名 |
set_password() | 設置密碼 |
get_fullname() | 返回姓名 |
last_login | 上次登錄時間 |
date_joined | 賬戶創建時間 |
練習. 實驗上面的處理函數的效果。
在Django中,我們還可以利用裝飾器,根據用戶的登錄狀況,來決定views.py中處理函數的顯示效果。相對於上面的if結構,裝飾器使用起來更加方便。下面的user_only()是views.py中的一個處理函數。
from django.contrib.auth.decorators import login_required from django.http import HttpResponse @login_required def user_only(request): return HttpResponse("<p>This message is for logged in user only.</p>")
注意上面的裝飾器login_required,它是Django預設的裝飾器。user_only()的回復結果只能被登錄用戶看到,而未登錄用戶將被引導到其他頁面。
Django中還有其它的裝飾器,用於修飾處理函數。相應的http回復,只能被特殊的用戶看到。比如user_passes_test,允許的用戶必須滿足特定標准,而這一標准是可以用戶自定義的。比如下面,在views.py中增添:
from django.contrib.auth.decorators import user_passes_test
from django.http import HttpResponse
def name_check(user): return user.get_username() == 'vamei' @user_passes_test(name_check) def specific_user(request): return HttpResponse("<p>for Vamei only</p>")
裝飾器帶有一個參數,該參數是一個函數對象name_check。當name_check返回真值,即用戶名為vamei時,specific_user的結果才能被用戶看到。
德國人羞澀的笑笑,“我確實對她有那么點好感。”
模板中的用戶
進一步,用戶是否登陸這一信息,也可以直接用於模板。比較原始的方式是把用戶信息直接作為環境數據,提交給模板。然而,這並不是必須的。事實上,Django為此提供了捷徑:我們可以直接在模板中調用用戶信息。比如下面的模板:
{% if user.is_authenticated %} <p>Welcome, my genuine user, my true love.</p> {% else %} <p>Sorry, not login, you are not yet my sweetheart. </p> {% endif %}
不需要環境變量中定義,我們就可以直接在模板中引用user。這里,模板中調用了user的一個方法,is_authenticated,將根據用戶的登錄情況,返回真假值。需要注意,和正常的Python程序不同,在Django模板中調用方法並不需要后面的括號。
練習. 增加處理函數,顯示該模板,然后查看不同登錄情況下的顯示結果。
管家冷不丁的說,“你認識他們?!”
用戶注冊
我們上面利用了admin管理頁面來增加和刪除用戶。這是一種簡便的方法,但並不能用於一般的用戶注冊的情境。我們需要提供讓用戶自主注冊的功能。這可以讓站外用戶提交自己的信息,生成自己的賬戶,並開始作為登陸用戶使用網站。
用戶注冊的基本原理非常簡單,即建立一個提交用戶信息的表格。表格中至少包括用戶名和密碼。相應的處理函數提取到這些信息后,建立User對象,並存入到數據庫中。
我們可以利用Django中的UserCreationForm,比較簡潔的生成表格,並在views.py中處理表格:
from django.contrib.auth.forms import UserCreationForm from django.shortcuts import render, redirect from django.core.context_processors import csrf def register(request): if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): new_user = form.save() return redirect("/") else: form = UserCreationForm() ctx = {'form': form} ctx.update(csrf(request)) return render(request, "register.html", ctx)
相應的模板register.html如下:
<form action="" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="Register">
</form>
“騙子,你們這些騙子”,庄園主怒吼着。
總結
正如我們上面提到的,用戶登陸系統的最大功能是區分登入和未登入用戶,向他們提供不同的內容和服務。
我們看到了用戶驗證的基本流程,也看到了如何在views.py和模板中區分用戶。
兩桿槍,一支指着德國人,一支指着姜戈。
歡迎閱讀“被解放的姜戈”系列文章。