當用戶想切換登陸帳號,或者想退出登陸狀態時,這時候就須要註銷已登陸的帳號。如今咱們來爲網站添加註銷登陸的功能,這個功能 Django 也已經爲咱們提供,咱們只需作一點簡單配置。html
註銷登陸
註銷登陸的視圖爲 logout,咱們簡單修改一下 index.html 的代碼,添加一個註銷登陸的按鈕:數據庫
templates/index.html
{% if user.is_authenticated %}
<p>你已登陸,歡迎你:<a href="#">{{ user.username }}</a></p> <button class="btn btn-default"><a href="{% url 'logout' %}">註銷登陸</a></button> {% else %} <p>你尚未登陸,請 <button class="btn btn-default"><a href="{% url 'login' %}">登陸</a></button> 或者 <button class="btn btn-default"><a href="{% url 'users:register' %}">註冊</a></button> </p> {% endif %}
若是你已經登錄,就會看到一個註銷登陸的按鈕,點擊該按鈕就會跳轉到註銷登陸已成功地頁面。再一次訪問首頁,你將看到登陸、註冊按鈕,說明你已經成功註銷登陸狀態了。瀏覽器
頁面跳轉
咱們以前在登陸、註冊和註銷的過程當中發現,登陸成功後會跳轉到一個 404 頁面,註冊成功後返回的是首頁,而註銷登陸後跳轉到了 Admin 後臺的註銷成功頁面。對於一個網站來講,比較好的用戶體驗是登陸、註冊和註銷後跳轉回用戶以前訪問的頁面。不然用戶在你的網站東跳轉西跳轉好不容易找到了想看的內容,結果他已登陸給他跳轉回了首頁,這會使用戶很是憤怒(我在有些網站就遇到過)。接下來咱們看看如何讓登陸、註冊和註銷後跳轉回用戶以前訪問的頁面。安全
登陸和註銷後返回當前頁面
在登陸和註銷的視圖函數中,Django 已經爲咱們處理了跳轉回用戶以前訪問頁面的流程。其實現的原理是,在登陸和註銷的流程中,始終傳遞一個 next 參數記錄用戶以前訪問頁面的 URL。所以,咱們須要作的就是在用戶訪問登陸或者註銷的頁面時,在 URL 中傳遞一個 next 參數給視圖函數,具體作法以下:數據結構
templates/index.html
<button class="btn btn-default"> <a href="{% url 'logout' %}?next={{ request.path }}">註銷登陸</a> </button> <button class="btn btn-default"> <a href="{% url 'login' %}?next={{ request.path }}">登陸</a> </button>
能夠看到,咱們在登陸和註銷的 URL 後加了 next 參數,其值爲 {{ request.path }}。request.path 是用戶當前訪問頁面的 URL。在 URL 中傳遞參數的方法就是在要傳遞的參數前加一個 ?而後寫上傳遞的參數名和參數值,用等號連接。關於在 URL 中傳遞參數具體請 HTTP 的相關協議。函數
爲了在整個登陸流程中記錄 next 的值,還須要在登陸表單中增長一個表單控件,用於傳遞 next 值。post
registration/login.html
<form class="form" action="{% url 'login' %}" method="post"> ... <button type="submit" class="btn btn-primary btn-block">登陸</button> <input type="hidden" name="next" value="{{ next }}"/> </form>
即在表單中增長了一個隱藏的 input 控件,其值爲 {{ next }},即以前經過 URL 參數傳遞給登陸視圖函數的,而後登陸視圖函數又將該值傳遞給了 login.html 模板。這樣在整個登陸流程中,始終有一個記錄着用戶在登陸前頁面 URL 的變量 next 在視圖和模板間來回傳遞,知道用戶登陸成功後再跳轉回 next 記錄的頁面 URL。網站
如今你能夠點擊登陸和註銷的按鈕來走一遍登陸和註銷流程,發現頁面跳轉已經符合咱們的需求了。不過還由一點點小瑕疵,就是若是用戶不是經過點擊登陸和註銷按鈕,而是直接在頁面輸入 URL 來訪問相關頁面話,那這個 next 就沒有值,從而沒法向以前那樣跳轉回用戶以前訪問的頁面。好比用戶想登陸,他直接在瀏覽器的地址欄輸入 /users/login/,因爲在 URL 中沒有傳遞 next,因此就沒法記錄用戶登陸前的頁面 URL,那在登陸成功後就沒法將他帶回登陸前的頁面了。固然這種狀況是極爲罕見的,不多有用戶會記住你網站的 URL 地址,但若是真有這樣的用戶,咱們就把他跳轉回首頁吧,由於沒有任何辦法記錄他以前訪問的頁面。要想把用戶跳轉回首頁,能夠在 settings 中作以下設置:url
LOGOUT_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
這樣,整個登陸和註銷流程就造成了一個閉環。若是用戶經過點擊登陸或者註銷按鈕登陸和註銷的話,在登陸或者註銷成功後就會被帶回登陸或者註銷前的頁面,不然將他帶回網站首頁。spa
註冊後返回當前頁面
相似的,咱們也但願用戶註冊後返回註冊前頁面。不過因爲註冊視圖函數是咱們本身寫的,以前的處理方式是用戶註冊成功後將其帶回網站首頁,所以須要修改一下注冊視圖函數:
users/views.py def register(request): # 從 get 或者 post 請求中獲取 next 參數值 # get 請求中,next 經過 url 傳遞,即 /?next=value # post 請求中,next 經過表單傳遞,即 <input type="hidden" name="next" value="{{ next }}"/> redirect_to = request.POST.get('next', request.GET.get('next', '')) # 只有當請求爲 POST 時,才表示用戶提交了註冊信息 if request.method == 'POST': # request.POST 是一個類字典數據結構,記錄了用戶提交的註冊信息 # 這裏提交的就是用戶名(username)、密碼(password)、確認密碼、郵箱(email) # 用這些數據實例化一個用戶註冊表單 form = RegisterForm(request.POST) # 驗證數據的合法性 if form.is_valid(): # 若是提交數據合法,調用表單的 save 方法將用戶數據保存到數據庫 form.save() if redirect_to: return redirect(redirect_to) else: return redirect('/') else: # 請求不是 POST,代表用戶正在訪問註冊頁面,展現一個空的註冊表單給用戶 form = RegisterForm() # 渲染模板 # 若是用戶正在訪問註冊頁面,則渲染的是一個空的註冊表單 # 若是用戶經過表單提交註冊信息,可是數據驗證不合法,則渲染的是一個帶有錯誤信息的表單 # 將記錄用戶註冊前頁面的 redirect_to 傳給模板,以維持 next 參數在整個註冊流程中的傳遞 return render(request, 'users/register.html', context={'form': form, 'next': redirect_to})
邏輯很是簡答,就是首先嚐試從用戶的 GET 或者 POST 請求中獲取 next 參數值,即在註冊成功後須要跳轉的 URL,若是有值,註冊成功後跳轉到該 URL,不然跳轉回首頁。同是不要忘記將該值傳給模板,以維持 next 參數在整個註冊流程中的傳遞。
接下來修改模板,和登陸模板的設置是同樣的:
registration/login.html
<button class="btn btn-default"> <a href="{% url 'users:register' %}?next={{ request.path }}">註冊</a> </button>
templates/users/register.html
<form class="form" action="{% url 'users:register' %}" method="post"> ... <button type="submit" class="btn btn-primary btn-block">註冊</button> <input type="hidden" name="next" value="{{ next }}"/> </form>
注意:在註冊視圖函數中,對 next 的任意值咱們都進行了跳轉,這可能致使一些安全問題。正確的作法應該是在跳轉前,對須要跳轉的 URL 作安全性檢查。不過這裏只做爲一個示例,在實際項目中請仔細考慮可能的安全後果,以及添加必要的安全性檢查代碼。
OK,如此修改之後,用戶的登陸、註冊和註銷流程的用戶體驗能夠造成一個比較良好閉環了。接下來就來實現修改密碼的功能。