用django創(chuàng)建一個社交網(wǎng)站-用戶認(rèn)證(轉(zhuǎn))

轉(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, email, 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)中然后返回一條成功消息盒蟆。

  • 請注意authenticationlogin中的不同點: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)框架中的UserGroup模型(models)赏枚。如下所示:

admin

使用管理站點創(chuàng)建一個新的用戶然后打開 http://127.0.0.1:8000/account/login/ 。你會看到被渲染過的模板(template)嚎京,包含一個登錄表單(form):

login

# 因為沒有css嗡贺,所以頁面是原始樣式

加個css樣式

https://pan.baidu.com/s/1bpaKg83 密碼: tzic ,里面示例代碼有base.css

加好后訪問

login-2

現(xiàn)在,只填寫一個字段保持另外一個字段為空進(jìn)行表單(from)提交鞍帝。在這例子中诫睬,你會看到這個表單(form)是無效的并且顯示了一個錯誤信息:

login-erorr

如果你輸入了一個不存在的用戶或者一個錯誤的密碼,你會得到一個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按鈕险毁。你會看到如下圖所示:

dashboard

你能看到My Dashboard section 通過CSS的作用高亮顯示因為它擁有一個selected class。因為當(dāng)前用戶已經(jīng)通過了認(rèn)證(authentication)所有用戶的第一個名字在右上角進(jìn)行了顯示们童。點擊Logout鏈接畔况。你會看到如下圖所示:

logout

在這個頁面中,你能看到用戶已經(jīng)登出慧库,然后跷跪,你無法看到當(dāng)前網(wǎng)站的任何菜單。在右上角現(xiàn)在顯示的是Log-in鏈接齐板。

如果你在你的登出頁面中看到了Django管理站點的登出頁面吵瞻,檢查項目settings.py中的INSTALLED_APPS,確保django.contrib.adminaccount應(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)登錄后,你會看到如下


修改密碼

點擊修改密碼頁面,按要求改完密碼后仇冯,會看到如下頁面:

after_change_password

登出再使用新的密碼進(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?鏈接。你會看到如下圖所示頁面:

fotgot-passwd

在這部分皇拣,你需要在你項目中的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按鈕嵌纲。你會看到如下圖所示頁面:

send_mail_done

當(dāng)你運行開發(fā)服務(wù)的時候看眼控制臺輸出俘枫。你會看到如下所示生成的e-mail:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逮走,隨后出現(xiàn)的幾起案子鸠蚪,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茅信,死亡現(xiàn)場離奇詭異盾舌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蘸鲸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門妖谴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人棚贾,你說我怎么就攤上這事窖维。” “怎么了妙痹?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵铸史,是天一觀的道長。 經(jīng)常有香客問我怯伊,道長琳轿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任耿芹,我火速辦了婚禮崭篡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吧秕。我一直安慰自己琉闪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布砸彬。 她就那樣靜靜地躺著颠毙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砂碉。 梳的紋絲不亂的頭發(fā)上蛀蜜,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音增蹭,去河邊找鬼滴某。 笑死,一個胖子當(dāng)著我的面吹牛滋迈,可吹牛的內(nèi)容都是我干的霎奢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼饼灿,長吁一口氣:“原來是場噩夢啊……” “哼椰憋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赔退,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后硕旗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窗骑,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年漆枚,在試婚紗的時候發(fā)現(xiàn)自己被綠了创译。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡墙基,死狀恐怖软族,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情残制,我是刑警寧澤立砸,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站初茶,受9級特大地震影響颗祝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恼布,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一螺戳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧折汞,春花似錦倔幼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至堕伪,卻和暖如春揖庄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背欠雌。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工蹄梢, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人富俄。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓禁炒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霍比。 傳聞我的和親對象是個殘疾皇子幕袱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容