請繼續在筆記3的基礎上開發。
導讀:
本章內容學習:
- 登錄表單(form)中的數據以GET/POST提交到服務器;
- Django驗證用戶名/密碼的正確性;
- 驗證成功後如何處理;
- 驗證失敗將錯誤提示返回客戶端。
一、先寫個登錄界面
打開…/sign/templates/index.html文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django Demo</title>
</head>
<body>
<h1>發佈會管理</h1>
<form>
<input name="username" type="text" placeholder="username" ><br>
<input name="password" type="password" placeholder="password" ><br>
<button id="btn" type="submit">登錄</button>
</form>
</body>
</html>
啓動D服務,訪問:http://127.0.0.1:8000/index/
上圖我們看到登錄界面已經寫好了,但它還不可用。
接下來我通GET與POST請求來實現登錄功能。
二、GET與POST請求
2.1GET請求
(get傳參方式:form method=“get”)
打開…/sign/templates/index.html文件
index.html
......
<form method="get">
<input name="username" type="text" placeholder="username" ><br>
<input name="password" type="password" placeholder="password" ><br>
<button id="btn" type="submit">登錄</button>
</form>
......
刷新登錄頁面,輸入用戶名/密碼(admin/admin123),單擊“登錄”按鈕
查看瀏覽器URL地址欄:
http://127.0.0.1:8000/index/?username=admin&password=admin123
GET方法會將用戶提交的數據添加到URL地址中,路徑後面跟問號“?”。username爲HTML代碼中<input>標籤的name屬性值(name=“username”),admin是我們在用戶名輸入框中填寫的用戶名。password=admin123的取值方式與用戶名相同。多個參數之間“&”符號隔開。
2.2POST請求
同樣是上面的代碼,將form表單中的屬性修改爲method=“post”,刷新頁面,輸入用戶名/密碼(admin/admin123),單擊“登錄”按鈕。彈出“CSRF verification failed. Request aborted.”
......
<form method="post">
<input name="username" type="text" placeholder="username" ><br>
<input name="password" type="password" placeholder="password" ><br>
<button id="btn" type="submit">登錄</button>
</form>
......
看到這個報錯,不要着急,靜下心來仔細閱讀上面的幫助信息。
這個錯誤是說我們在使用Django的模板未正確使用CSRF(Cross-Site Request Forgery “跨站請求僞造”)令牌!Django針對CSRF的保護措施是在生成的每個表單中放置一個自動生成的令牌,通過這個令牌判斷POST請求是否來自同一個網站。
之前的模板都是純粹的HTML,這裏首次用到Django的模板,使用“模板標籤”(TemplateTag)添加CSRF令牌。在from表單中添加{% csrf_token %}。
<form method="post">
<input name="username" type="text" placeholder="username" ><br>
<input name="password" type="password" placeholder="password" ><br>
<button id="btn" type="submit">登錄</button>
{% csrf_token %}
</form>
然後,刷新頁面,輸入用戶名/密碼(admin/admin123),單擊“登錄”按鈕。按F12調試工具查看POST請求,我們會看到除了“usrnname"和”password“參數外,還多了一個”csrfmiddlewaretoken“的參數。當頁面向Django服務器發送一個POST請求時,服務器端要求客端加上”csrfmiddlewaretoken“字段,該字段的值爲當前會話ID加上一個密鑰的散列值。
如果想忽略掉該檢查,那麼可以在…/guest/settings.py文件中註釋掉csrf。
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
三、處理登錄請求
那麼Django是如何接收請求的數據並加以處理的呢?可以通過form表單的action屬性來指定提交的路徑。
打開index.html文件,添加內容如下:
......
<form method="post" action="/login_action/">
......
當我們填寫用戶名/密碼,單擊”登錄“按鈕時,由http://127.0.0.1:8000/login_action/路徑來提交登錄請求。所以,打開…/guest/urls.py文件添加login_action的路由。
from sign import views #導入sign應用views文件
urlpatterns = [
......
url(r'login_action/$',views.login_action),
]
登錄請求由views.py視圖文件的login_action函數來處理,打開sign/views.py文件,創建login_action視圖函數。
......
# 登錄動作
def login_action(request):
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
if username == 'admin' and password == 'admin123':
return HttpResponse('登錄成功!')
else:
return render(request,'index.html',{'error':'用戶名密碼錯誤!'})
分析:
1、首先,通過request.method得到客戶端的請求方式,並判斷其是否爲POST方式的請求。
2、接着,通過request.POST來獲取POST請求。通過.get()方法獲取“username”和“password”所獲取的用戶名/密碼(admin/admin123)。如果參數爲空,則返回一個空的字符串。
3、最後,通過if語句判斷username和passwoed的值是否爲“admin/admin123”。如果是則通過HttpResponse類返回字符串“登錄成功”。否則,將通過render返回index.html登錄頁面,並且順帶返回錯誤提示的字典{‘error’:‘用戶名和密碼錯誤!’}。
但是,登錄頁面並沒有顯示錯誤提示的位置,打開index.html頁面修改如下:
<form method="post" action="/login_action/">
<input name="username" type="text" placeholder="username" ><br>
<input name="password" type="password" placeholder="password" ><br>
{{ error }}<br>
<button id="btn" type="submit">登錄</button>
{% csrf_token %}
</form>
使用Django的模板語言,添加{{ error }}
,它對應render返回字典中的key,即‘error’在登錄失敗的頁面中顯示對應的value,即’用戶名密碼錯誤!‘。
好了,現在來體驗下登錄功能。
四、登錄成功頁
登錄成功返回”登錄成功!”字符串只是一種臨時方案,只是爲了方便驗證登錄的處理邏輯,現在驗證沒有問題之後,需要通過HTML頁面來替換。
首先,創建…/templates/event_manage.html頁面。(發佈會管理頁面)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>發佈會管理系統</title>
</head>
<body>
<h1>登錄成功!</h1>
</body>
</html>
打開…/sign/views.py文件,修改內容:
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
......
# 登錄動作
def login_action(request):
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
if username == 'admin' and password == 'admin123':
return HttpResponseRedirect('/event_manage/')
else:
return render(request,'index.html',{'error':'用戶名密碼錯誤!'})
# 發佈會管理
def event_manage(request):
return render(request,"event_manage.html")
此處用到一個新類HttpResponseRedirect,它可以對路徑進行重定向,從而將登錄成功之後的請求指向/event_manage/目錄,即:http://127.0.0.1:8000/event_manage/
創建event_manage函數,用於返回發佈會管理頁面event_manage.html。
最後,我們要記的在…/guest.urls.py 文件中添加event_manage/的路由。
from sign import views #導入sign應用views文件
urlpatterns = [
......
url(r'event_manage/$',views.event_manage),
]
再來登錄一下,試試修改後的功能吧!