轉(zhuǎn)自:http://www.reibang.com/p/06670f9aa439
第四章
創(chuàng)建一個社交網(wǎng)站
在上一章中,你學(xué)習(xí)了如何創(chuàng)建站點地圖(sitemaps)和feeds捡偏,你還為你的blog應(yīng)用創(chuàng)建了一個搜索引擎纱扭。在本章中衡怀,你將開發(fā)一個社交應(yīng)用。你會為用戶創(chuàng)建一些功能安疗,例如:登錄抛杨,登出,編輯荐类,以及重置他們的密碼怖现。你會學(xué)習(xí)如何為你的用戶創(chuàng)建一個定制的profile,你還會為你的站點添加社交認(rèn)證。
本章將會覆蓋以下幾點:
- 使用認(rèn)證(authentication)框架
- 創(chuàng)建用戶注冊視圖(views)
- 通過一個定制的profile模型(model)擴(kuò)展User模型(model)
- 使用python-social-auth添加社交認(rèn)證
讓我們開始創(chuàng)建我們的新項目吧。
創(chuàng)建一個社交網(wǎng)站項目
我們要創(chuàng)建一個社交應(yīng)用允許用戶分享他們在網(wǎng)上找到的圖片删豺。我們需要為這個項目構(gòu)建以下元素:
- 一個用來給用戶注冊啤贩,登錄,編輯他們的profile纯趋,以及改變或重置密碼的認(rèn)證(authentication)系統(tǒng)
- 一個允許用戶用來關(guān)注其他人的關(guān)注系統(tǒng)(這里原文是follow,‘跟隨’,感覺用‘關(guān)注’更加適合點)
- 為用戶從其他任何網(wǎng)站分享過來的圖片進(jìn)行展示和打上書簽
- 每個用戶都有一個活動流允許用戶看到他們關(guān)注的人上傳的內(nèi)容
本章主要講述第一點茫船。
開始你的社交網(wǎng)站項目
運行以下命令來創(chuàng)建一個新項目:
django-admin statproject bookmarks
在創(chuàng)建好一個初始的項目結(jié)構(gòu)以后,使用以下命令進(jìn)入你的項目目錄并且創(chuàng)建一個新的應(yīng)用命名為account:
cd bookmarks/django-admin startapp account
請記住在你的項目中激活一個新應(yīng)用需要在settings.py文件中的INSTALLED_APPS設(shè)置中添加它扭屁。將新應(yīng)用的名字添加在INSTALLED_APPS列中的所有已安裝應(yīng)用的最前面算谈,如下所示:
INSTALLED_APPS = (
'account',
# ...
)
運行下一條命令為INSTALLED_APPS中默認(rèn)包含的應(yīng)用模型(models)同步到數(shù)據(jù)庫中:
python manage.py migrate
我們將要使用認(rèn)證(authentication)框架來構(gòu)建一個認(rèn)證系統(tǒng)到我們的項目中。
使用Django認(rèn)證(authentication)框架
Django擁有一個內(nèi)置的認(rèn)證(authentication)框架用來操作用戶認(rèn)證(authentication)料滥,會話(sessions)然眼,權(quán)限(permissions)以及用戶組。這個認(rèn)證(authentication)系統(tǒng)包含了一些普通用戶的操作視圖(views)葵腹,例如:登錄高每,登出,修改密碼以及重置密碼礁蔗。
這個認(rèn)證(authentication)框架位于django.contrib.auth觉义,被其他Django的contrib包調(diào)用。請記住你使用過這個認(rèn)證(authentication)框架在第一章 創(chuàng)建一個Blog應(yīng)用中用來為你的blog應(yīng)用創(chuàng)建了一個超級用戶來使用管理站點浴井。
當(dāng)你使用startproject命令創(chuàng)建一個新的Django項目晒骇,認(rèn)證(authentication)框架已經(jīng)在你的/項目設(shè)置中默認(rèn)包含。它是由django.contrib.auth應(yīng)用和你的項目設(shè)置中的MIDDLEWARE_CLASSES中的兩個中間件類組成磺浙,如下:
- AuthenticationMiddlwware:使用會話(sessions)將用戶和請求(requests)進(jìn)行關(guān)聯(lián)
- SessionMiddleware:通過請求(requests)操作當(dāng)前會話(sessions)
中間件就是一個在請求和響應(yīng)階段帶有全局執(zhí)行方法的類洪囤。你會在本書中的很多場景中使用到中間件。你將會學(xué)習(xí)如何創(chuàng)建一個定制的中間件在第十三章 Going Live(譯者注:啥時候能翻譯到八貉酢)瘤缩。
這個認(rèn)證(authentication)系統(tǒng)還包含了以下模型(models):
- User:一個用戶模型(model)包含基礎(chǔ)字段;這個模型(model)的主要字段有:
username
,password
,first_name
,last_name
,is_active
伦泥。
- Group:一個組模型(model)用來分類用戶
- Permission:執(zhí)行特定操作的標(biāo)識
這個框架還包含默認(rèn)的認(rèn)證(authentication)視圖(views)和表單(forms)剥啤,我們之后會用到锦溪。
創(chuàng)建一個log-in視圖(view)
我們將要開始使用Django認(rèn)證(authentication)框架來允許用戶登錄我們的網(wǎng)站。我們的視圖(view)需要執(zhí)行以下操作來登錄用戶:
1府怯、通過提交的表單(form)獲取username和password
2刻诊、通過存儲在數(shù)據(jù)庫中的數(shù)據(jù)對用戶進(jìn)行認(rèn)證
3、檢查用戶是否可用
4牺丙、登錄用戶到網(wǎng)站中并且開始一個認(rèn)證(authentication)會話(session)
首先则涯,我們要創(chuàng)建一個登錄表單(form)。在你的account應(yīng)用目錄下創(chuàng)建一個新的forms.py文件冲簿,添加如下代碼:
from django import forms
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
這個表單(form)被用來通過數(shù)據(jù)庫認(rèn)證用戶粟判。請注意,我們使用PsswordInput控件來渲染HTMLinput
元素峦剔,包含type="password
屬性档礁。編輯你的account應(yīng)用中的views.py文件,添加如下代碼:
from django.http import HttpResponse
from django.shortcuts import render
from django.contrib.auth import authenticate, login
from .forms import LoginForm
def user_login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
user = authenticate(username=cd['username'],
password=cd['password'])
if user is not None:
if user.is_active:
login(request, user)
return HttpResponse('Authenticated successfully')
else:
return HttpResponse('Disabled account')
else:
return HttpResponse('Invalid login')
else:
form = LoginForm()
return render(request, 'account/login.html', {'form': form})
以上就是我們在視圖(view)中所作的基本登錄操作:當(dāng)user_login被一個GET請求(request)調(diào)用羊异,我們實例化一個新的登錄表單(form)通過form = LoginForm()
在模板(template)中展示它事秀。當(dāng)用戶通過POST方法提交表單(form),我們執(zhí)行以下操作:
1野舶、使用提交的數(shù)據(jù)實例化表單(form)通過使用
form = LoginForm(request.POST)
2、檢查這個表單是否有效宰衙。如果無效平道,我們在模板(template)中展示表單錯誤信息(舉個例如,比如用戶沒有填寫其中一個字段就進(jìn)行提交)
3供炼、如果提交的數(shù)據(jù)是有效的一屋,我們通過數(shù)據(jù)庫對這個用戶進(jìn)行認(rèn)證(authentication)通過使用authenticate()
方法。這個方法帶入一個username和一個password并且返回一個用戶對象如果這個用戶成功的進(jìn)行了認(rèn)證袋哼,或者是None冀墨。如果用戶沒有被認(rèn)證通過,我們返回一個HttpResponse展示一條消息涛贯。
4诽嘉、如果這個用戶認(rèn)證(authentication)成功,我們使用is_active
屬性來檢查用戶是否可用弟翘。這是一個Django的User模型(model)屬性虫腋。如果這個用戶不可用,我們返回一個HttpResponse展示信息稀余。
5悦冀、如果用戶可用,我們登錄這個用戶到網(wǎng)站中睛琳。我們通過調(diào)用login()
方法集合用戶到會話(session)中然后返回一條成功消息盒蟆。
- 請注意authentication和login中的不同點:authenticate()檢查用戶認(rèn)證信息然后返回一個用戶對象如果用戶是正確的踏烙;login()集合用戶到當(dāng)前的會話(session)中。
現(xiàn)在历等,你需要為這個視圖(view)創(chuàng)建一個URL模式讨惩。在你的account應(yīng)用目錄下創(chuàng)建一個新的urls.py文件,添加如下代碼:
from django.conf.urls import url
from . import views
urlpatterns = [
# post views
url(r'^login/$', views.user_login, name='login'),
]
編輯位于你的bookmarks項目目錄下的urls.py文件募闲,將account應(yīng)用下的URL模式包含進(jìn)去:
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^account/',include('account.urls')),
]
這個登錄視圖(view)現(xiàn)在已經(jīng)可以通過URL進(jìn)行訪問〔脚В現(xiàn)在是時候為這個視圖(view)創(chuàng)建一個模板。
因為之前你沒有這個項目的任何模板浩螺,你可以開始創(chuàng)建一個主模板(template)可以被登錄模板(template)繼承使用靴患。創(chuàng)建以下文件和結(jié)構(gòu)在account應(yīng)用目錄中:
templates/account/base.html, templates/account/login.html
編輯base.html文件添加如下代碼:
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
<link href="{% static "css/base.css" %}" rel="stylesheet">
</head>
<body>
<div id="header">
<span class="logo">Bookmarks</span>
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
以上將是這個網(wǎng)站的基礎(chǔ)模板(template)要出。就像我們在上一章項目中做過的一樣鸳君,我們在這個住模板(template)中包含了CSS樣式。你可以在本章的示例代碼中找到這些靜態(tài)文件患蹂。復(fù)制示例代碼中的account應(yīng)用下的static/目錄到你的項目中的相同位置或颊,這樣你就可以使用這些靜態(tài)文件了。
基礎(chǔ)模板(template)定義了一個title和一個content區(qū)塊可以被繼承的子模板(template)填充內(nèi)容传于。
讓我們?yōu)槲覀兊牡卿洷韱危╢orm)創(chuàng)建模板(template)囱挑。打開account/login.html模板(template)添加如下代碼:
{% extends "account/base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
<h1>Log-in</h1>
<p>Please, use the following form to log-in:</p>
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Log-in"></p>
</form>
{% endblock %}
這個模板(template)包含了視圖(view)中實例化的表單(form)。因為我們的表單(form)將會通過POST方式進(jìn)行提交沼溜,所以我們包含了{(lán)% csrf_token %}
模板(template)標(biāo)簽(tag)用來通過CSRF保護(hù)平挑。你已經(jīng)學(xué)習(xí)過CSRF保護(hù)在第二章 使用高級特性擴(kuò)展你的博客應(yīng)用。
目前還沒有用戶在你的數(shù)據(jù)庫中系草。你首先需要創(chuàng)建一個超級用戶用來登錄管理站點來管理其他的用戶通熄。打開命令行執(zhí)行python manage.py createsuperuser
。填寫username,e-mail以及password找都。之后通過命令python manage.py runserver
運行開發(fā)環(huán)境唇辨,然后在你的瀏覽器中打開 http://127.0.0.1:8000/admin/ 。使用你剛才創(chuàng)建的username和passowrd來進(jìn)入管理站點能耻。你會看到Django管理站點包含Django認(rèn)證(authentication)框架中的User和Group模型(models)赏枚。如下所示:
使用管理站點創(chuàng)建一個新的用戶然后打開 http://127.0.0.1:8000/account/login/ 。你會看到被渲染過的模板(template)嚎京,包含一個登錄表單(form):
# 因為沒有css嗡贺,所以頁面是原始樣式
加個css樣式
https://pan.baidu.com/s/1bpaKg83 密碼: tzic ,里面示例代碼有base.css
加好后訪問
現(xiàn)在,只填寫一個字段保持另外一個字段為空進(jìn)行表單(from)提交鞍帝。在這例子中诫睬,你會看到這個表單(form)是無效的并且顯示了一個錯誤信息:
如果你輸入了一個不存在的用戶或者一個錯誤的密碼,你會得到一個Invalid login信息帕涌。
如果你輸入了有效的認(rèn)證信息摄凡,你會得到一個Authenticated successfully消息续徽。
使用Django認(rèn)證(authentication)視圖(views)
Django包含了一些表單(forms)和視圖(views)在認(rèn)證(authentication)框架中讓你可以立刻(straightaway)使用。你之前創(chuàng)建的登錄視圖(view)是一個非常的練習(xí)用來理解Django中的用戶認(rèn)證(authentication)過程亲澡。無論如何钦扭,你可以使用默認(rèn)的Django認(rèn)證(authentication)視圖(views)在大部分的例子中。
Django提供以下視圖(views)來處理認(rèn)證(authentication):
- login:操作表單(form)中的登錄然后登錄一個用戶
- logout:登出一個用戶
- logout_then_login:登出一個用戶然后重定向這個用戶到登錄頁面
Django提供以下視圖(views)來操作密碼修改:
- password_change:操作一個表單(form)來修改用戶密碼
- password_change_done:當(dāng)用戶成功修改他的密碼后提供一個成功提示頁面
Django還包含了以下視圖(views)允許用戶重置他們的密碼:
- password_reset:允許用戶重置他的密碼床绪。它會生成一條帶有一個token的一次性使用鏈接然后發(fā)送到用戶的郵箱中客情。
- password_reset_done:告知用戶已經(jīng)發(fā)送了一封可以用來重置密碼的郵件到他的郵箱中。
- password_reset_complete:當(dāng)用戶重置完成他的密碼后提供一個成功提示頁面癞己。
以上的視圖(views)可以幫你節(jié)省很多時間當(dāng)你創(chuàng)建一個帶有用戶賬號的網(wǎng)站膀斋。這些視圖(views)使用的默認(rèn)值你可以進(jìn)行覆蓋,例如需要渲染的模板位置或者視圖(view)需要使用到的表單(form)痹雅。
你可以通過訪問 https://docs.djangoproject.com/en/1.8/topics/auth/default/#module-django.contrib.auth.views 獲取更多內(nèi)置的認(rèn)證(authentication)視圖(views)信息仰担。
登錄和登出視圖(views)
編輯你的account應(yīng)用下的urls.py文件,如下所示:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^login/$', 'django.contrib.auth.views.login', name='login'),
url(r'^logout/$', 'django.contrib.auth.views.logout', name='logout'),
url(r'^logout-then-login/$', 'django.contrib.auth.views.logout_then_login', name='logout_then_login'),
]
這種寫法會報錯绩社,view must be a callable or a list/tuple in the case of include()
解決:
from django.conf.urls import url
from .views import dashboard
from django.contrib.auth import views
urlpatterns = [
# post views
url(r'^login/$', views.login, name='login'),
url(r'^logout/$', views.logout, name='logout'),
url(r'^logout-then-login/$', views.logout_then_login, name='logout_then_login'),
]
我們將之前創(chuàng)建的user_login視圖(view)URL模式進(jìn)行注釋摔蓝,然后使用Django認(rèn)證(authentication)框架提供的login視圖(view)。
在你的account應(yīng)用中的template目錄下創(chuàng)建一個新的目錄命名為registration愉耙。這個路徑是Django認(rèn)證(authentication)視圖(view)期望你的認(rèn)證(authentication)模塊(template)默認(rèn)的存放路徑贮尉。在這個新目錄中創(chuàng)建一個新的文件,命名為login.html朴沿,然后添加如下代碼:
{% extends "base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
<h1>Log-in</h1>
{% if form.errors %}
<p>
Your username and password didn't match.
Please try again.
</p>
{% else %}
<p>Please, use the following form to log-in:</p>
{% endif %}
<div class="login-form">
<form action="{% url 'login' %}" method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<p><input type="submit" value="Log-in"></p>
</form>
</div>
{% endblock %}
這個登錄模板(template)和我們之前創(chuàng)建的基本類似绘盟。Django默認(rèn)使用位于django.contrib.auth.forms中的AuthenticationForm。這個表單(form)會嘗試對用戶進(jìn)行認(rèn)證如果登錄不成功就會拋出一個驗證錯誤悯仙。在這個例子中,我們可以在模板(template)中使用{% if form.errors %}來找到錯誤如果用戶提供了錯誤的認(rèn)證信息吠卷。
請注意锡垄,我們添加了一個隱藏的HTML<input>元素來提交叫做next的變量值。這個變量是登錄視圖(view)的首個設(shè)置當(dāng)你在請求(request)中傳遞一個next參數(shù)(舉個例子:http://127.0.0.1:8000/account/login/?next=/account/)祭隔。
next參數(shù)必須是一個URL货岭。當(dāng)這個參數(shù)被給予的時候,Django登錄視圖(view)將會在用戶登錄完成后重定向到給予的URL疾渴。
現(xiàn)在千贯,在registrtion模板(template)目錄下創(chuàng)建一個logged_out.html模板(template)添加如下代碼:
{% extends "base.html" %}
{% block title %}Logged out{% endblock %}
{% block content %}
<h1>Logged out</h1>
<p>You have been successfully logged out. You can <a href="{% url "login" %}">log-in again</a>.</p>
{% endblock %}
這個模板(template)Django會在用戶登出的時候進(jìn)行展示。
在添加了URL模式以及登錄和登出視圖(view)的模板之后搞坝,你的網(wǎng)站已經(jīng)準(zhǔn)備好讓用戶使用Django認(rèn)證(authentication)視圖進(jìn)行登錄搔谴。
請注意,在我們的地址配置中包含的logtou_then_login視圖(view)不需要任何模板(template)桩撮,因為它執(zhí)行了一個重定向到登錄視圖(view)敦第。
現(xiàn)在峰弹,我們要創(chuàng)建一個新的視圖(view)來顯示一個dashboard給用戶當(dāng)他或她登錄他們的賬號。打開你的account應(yīng)用中的views.py文件芜果,添加以下代碼:
from django.contrib.auth.decorators import login_required
@login_required
def dashboard(request):
return render(request, 'account/dashboard.html', {'section': 'dashboard'})
我們使用認(rèn)證authentication
框架的login_required裝飾器decorator
裝飾我們的視圖view
鞠呈。login_required裝飾器decorator
會檢查當(dāng)前用戶是否通過認(rèn)證,如果用戶通過認(rèn)證,它會執(zhí)行裝飾的視圖view
右钾,如果用戶沒有通過認(rèn)證蚁吝,它會把用戶重定向到帶有一個名為next的GET參數(shù)的登錄URL,該GET參數(shù)保存的變量為用戶當(dāng)前嘗試訪問的頁面URL舀射。通過這些動作窘茁,登錄視圖view
會將登錄成功的用戶重定向到用戶登錄之前嘗試訪問過的URL。請記住我們在登錄模板template
中的登錄表單form
中添加的隱藏<input>就是為了這個目的后控。
我們還定義了一個section變量庙曙。我們會使用該變量來跟蹤用戶在站點中正在查看的頁面。多個視圖(views)可能會對應(yīng)相同的section浩淘。這是一個簡單的方法用來定義每個視圖(view)對應(yīng)的section捌朴。
現(xiàn)在,你需要創(chuàng)建一個給dashboard視圖(view)使用的模板(template)张抄。在templates/account/目錄下創(chuàng)建一個新文件命名為dashboard.html砂蔽。添加如下代碼:
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<h1>Dashboard</h1>
<p>Welcome to your dashboard.</p>
{% endblock %}
之后,為這個視圖(view)在account應(yīng)用中的urls.py文件中添加如下URL模式:
url(r'^$', views.dashboard, name='dashboard'),
編輯你的項目的settings.py文件署惯,添加如下代碼:
from django.core.urlresolvers import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('dashboard')
LOGIN_URL = reverse_lazy('login')
LOGOUT_URL = reverse_lazy('logout')
這些設(shè)置的意義:
- LOGIN_REDIRECT_URL:告訴Django用戶登錄成功后如果contrib.auth.views.login視圖(view)沒有獲取到next參數(shù)將會默認(rèn)重定向到哪個URL左驾。
- LOGIN_URL:重定向用戶登錄的URL(例如:使用login_required裝飾器(decorator))。
- LOGOUT_URL:重定向用戶登出的URL极谊。
我們使用reverse_laze()來動態(tài)構(gòu)建URL通過它們的名字诡右。reverse_laze()方法reverses URLs就像reverse()所做的一樣,但是你可以使用它當(dāng)你需要reverse URLs在你項目的URL配置讀取之前轻猖。
讓我們總結(jié)下目前為止我們都做了哪些工作:
你在項目中添加了Django內(nèi)置的認(rèn)證(authentication)登錄和登出視圖(views)帆吻。
你為每一個視圖(view)創(chuàng)建了定制的模板(templates),并且定義了一個簡單的視圖(view)讓用戶登錄后進(jìn)行重定向咙边。
最后猜煮,你配置了你的Django設(shè)置使用默認(rèn)的URLs。
現(xiàn)在败许,我們要給我們的主模板(template)添加登錄和登出鏈接將所有的一切都連接起來王带。
為了做到這點,我們必須確定無論用戶是已登錄狀態(tài)還是沒有登錄的時候市殷,都會顯示適當(dāng)?shù)逆溄鱼底Mㄟ^認(rèn)證(authentication)中間件當(dāng)前的用戶被集合在HTTP請求(request)對象中。你可以訪問用戶信息通過使用request.user
。你會防線一個用戶對象在請求(request)中盟戏,即使這個用戶并沒有認(rèn)證通過绪妹。一個非認(rèn)證的用戶在請求(request)被設(shè)置成一個AnonymousUser的實例。一個最好的方法來檢查當(dāng)前的用戶是否通過認(rèn)證是通過調(diào)用request.user.is_authenticated()
柿究。
編輯你的base.html, 如下所示:
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
<link href="{% static "css/base.css" %}" rel="stylesheet">
</head>
<body>
<div id="header">
<span class="logo">Bookmarks</span>
{% if request.user.is_authenticated %}
<ul class="menu">
<li {% if section == "dashboard" %}class="selected"{% endif %}>
<a href="{% url "dashboard" %}">My dashboard</a>
</li>
<li {% if section == "images" %}class="selected"{% endif %}>
<a href="#">Images</a>
</li>
<li {% if section == "people" %}class="selected"{% endif %}>
<a href="#">People</a>
</li>
</ul>
{% endif %}
<span class="user">
{% if request.user.is_authenticated %}
Hello {{ request.user.first_name }},
<a href="{% url "logout" %}">Logout</a>
{% else %}
<a href="{% url "login" %}">Log-in</a>
{% endif %}
</span>
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
就像你所看到的邮旷,我們只給通過認(rèn)證(authentication)的用戶顯示站點菜單。我們還檢查當(dāng)前的section來給對應(yīng)的<li>
組件添加一個selected的class屬性來使當(dāng)前section在菜單中進(jìn)行高亮顯示通過使用CSS蝇摸。我們還顯示用戶的第一個名字和一個登出的鏈接如果用戶已經(jīng)通過認(rèn)證(authentication)婶肩,否則,就是一個登出鏈接貌夕。
現(xiàn)在律歼,在瀏覽器中打開 http://127.0.0.1:8000/account/login/ 。你會看到登錄頁面啡专。輸入可用的用戶名和密碼然后點擊Log-in按鈕险毁。你會看到如下圖所示:
你能看到My Dashboard section 通過CSS的作用高亮顯示因為它擁有一個selected class。因為當(dāng)前用戶已經(jīng)通過了認(rèn)證(authentication)所有用戶的第一個名字在右上角進(jìn)行了顯示们童。點擊Logout鏈接畔况。你會看到如下圖所示:
在這個頁面中,你能看到用戶已經(jīng)登出慧库,然后跷跪,你無法看到當(dāng)前網(wǎng)站的任何菜單。在右上角現(xiàn)在顯示的是Log-in鏈接齐板。
如果你在你的登出頁面中看到了Django管理站點的登出頁面吵瞻,檢查項目settings.py中的INSTALLED_APPS,確保django.contrib.admin在account應(yīng)用的后面。每個模板(template)被定位在同樣的相對路徑時甘磨,Django模板(template)讀取器將會使用它找到的第一個應(yīng)用中的模板(templates)橡羞。
修改密碼視圖(views)
我們還需要我們的用戶在登錄成功后可以進(jìn)行修改密碼。我們要集成Django認(rèn)證(authentication)視圖(views)來修改密碼济舆。打開account應(yīng)用中的urls.py文件尉姨,添加如下URL模式:
url(r'^password-change/$', views.password_change, name='password_change'),
url(r'^password-change/done/$', views.password_change_done, name='password_change_done'),
password_change視圖(view)將會操作表單(form)進(jìn)行修改密碼,password_change_done將會顯示一條成功信息當(dāng)用戶成功的修改他的密碼吗冤。讓我們?yōu)槊總€視圖(view)創(chuàng)建一個模板(template)。
在你的account應(yīng)用templates/registration/目錄下添加一個新的文件命名為password_form.html九府,在文件中添加如下代碼:
{% extends "base.html" %}
{% block title %}Change you password{% endblock %}
{% block content %}
<h1>Change you password</h1>
<p>Use the form below to change your password.</p>
<form action="." method="post">
{{ form.as_p }}
<p><input type="submit" value="Change"></p>
{% csrf_token %}
</form>
{% endblock %}
這個模板(template)包含了修改密碼的表單(form)∽滴粒現(xiàn)在,在相同的目錄下創(chuàng)建另一個文件侄旬,命名為password_change_done.html肺蔚,為它添加如下代碼:
{% extends "base.html" %}
{% block title %}Password changed{% endblock %}
{% block content %}
<h1>Password changed</h1>
<p>Your password has been successfully changed.</p>
{% endblock %}
這個模板(template)只包含顯示一條成功的信息 當(dāng)用戶成功的修改他們的密碼。
在base.html的 {% if request.user.is_authenticated %}
下面加一行
<a href="{% url "password_change" %}"> 修改密碼 </a>
刷新頁面即可看到儡羔,如果你的用戶沒有登錄宣羊,瀏覽器會重定向你到登錄頁面璧诵。在你成功認(rèn)證(authentication)登錄后,你會看到如下
點擊修改密碼頁面,按要求改完密碼后仇冯,會看到如下頁面:
登出再使用新的密碼進(jìn)行登錄來驗證每件事是否如預(yù)期一樣工作之宿。
重置密碼視圖(views)
在account應(yīng)用urls.py文件中為密碼重置添加如下URL模式:
# restore password urls
url(r'^password-reset/$', 'django.contrib.auth.views.password_reset', name='password_reset'),
url(r'^password-reset/done/$', 'django.contrib.auth.views.password_reset_done', name='password_reset_done'),
url(r'^password-reset/confirm/(?P<uidb64>[-\w]+)/(?P<token>[-\w]+)/$',
'django.contrib.auth.views.password_reset_confirm', name='password_reset_confirm'),
url(r'^password-reset/complete/$', 'django.contrib.auth.views.password_reset_complete',
name='password_reset_complete'),
在你的account應(yīng)用templates/registration/目錄下添加一個新的文件命名為password_reset_form.html,為它添加如下代碼:
{% extends "base.html" %}
{% block title %}Reset your password{% endblock %}
{% block content %}
<h1>Forgotten your password?</h1>
<p>Enter your e-mail address to obtain a new password.</p>
<form action="." method="post">
{{ form.as_p }}
<p><input type="submit" value="Send e-mail"></p>
{% csrf_token %}
</form>
{% endblock %}
現(xiàn)在苛坚,在相同的目錄下添加另一個文件命名為password_reset_email.html比被,為它添加如下代碼:
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol }}://{{ domain }}{% url "password_reset_confirm" uidb64=uid token=token %}
Your username, in case you've forgotten: {{ user.get_username }}
這個模板(template)會被用來渲染發(fā)送給用戶的重置密碼郵件。
在相同目錄下添加另一個文件命名為*password_reset_done.html泼舱,為它添加如下代碼:
{% extends "base.html" %}
{% block title %}Reset your password{% endblock %}
{% block content %}
<h1>Reset your password</h1>
<p>We've emailed you instructions for setting your password.</p>
<p>If you don't receive an email, please make sure you've entered the address you registered with.</p>
{% endblock %}
再創(chuàng)建另一個模板(template)命名為passowrd_reset_confirm.html等缀,為它添加如下代碼:
{% extends "base.html" %}
{% block title %}Reset your password{% endblock %}
{% block content %}
<h1>Reset your password</h1>
{% if validlink %}
<p>Please enter your new password twice:</p>
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Change my password" /></p>
</form>
{% else %}
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
{% endif %}
{% endblock %}
在以上模板中,如果重置鏈接是有效的我們將會進(jìn)行檢查娇昙。Django重置密碼視圖(view)會設(shè)置這個變量然后將它帶入這個模板(template)的上下文環(huán)境中尺迂。如果重置鏈接有效,我們展示用戶密碼重置表單(form)冒掌。
創(chuàng)建另一個模板(template)命名為password_reset_complete.html噪裕,為它添加如下代碼:
{% extends "base.html" %}
{% block title %}Password reset{% endblock %}
{% block content %}
<h1>Password set</h1>
<p>Your password has been set. You can <a href="{% url "login" %}">log in now</a></p>
{% endblock %}
最后,編輯account應(yīng)用中的/registration/login.html模板(template)宋渔,添加如下代碼在<form>
元素之后:
<p><a href="{% url "password_reset" %}">Forgotten your password?</a></p>
現(xiàn)在州疾,在瀏覽器中打開 http://127.0.0.1:8000/account/login/ 然后點擊Forgotten your password?鏈接。你會看到如下圖所示頁面:
在這部分皇拣,你需要在你項目中的settings.py中添加一個SMTP配置严蓖,這樣Django才能發(fā)送e-mails。我們已經(jīng)學(xué)習(xí)過如何添加e-mail配置在第二章 使用高級特性來優(yōu)化你的blog氧急。當(dāng)然颗胡,在開發(fā)期間,我們可以配置Django在標(biāo)準(zhǔn)輸出中輸出e-mail內(nèi)容來代替通過SMTP服務(wù)發(fā)送郵件吩坝。Django提供一個e-mail后端來輸出e-mail內(nèi)容到控制器中毒姨。編輯項目中settings.py文件,添加如下代碼:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
EMAIL_BACKEND設(shè)置這個類用來發(fā)送e-mails钉寝。
回到你的瀏覽器中弧呐,填寫一個存在用戶的e-mail地址,然后點擊Send e-mail按鈕嵌纲。你會看到如下圖所示頁面:
當(dāng)你運行開發(fā)服務(wù)的時候看眼控制臺輸出俘枫。你會看到如下所示生成的e-mail: