第四章 創(chuàng)建一個(gè)社交網(wǎng)站

4 創(chuàng)建一個(gè)社交網(wǎng)站

在上一章中,你學(xué)習(xí)了如何創(chuàng)建站點(diǎn)地圖和訂閱,并且為博客應(yīng)用構(gòu)建了一個(gè)搜索引擎。在這一章中,你會開發(fā)一個(gè)社交應(yīng)用。你會為用戶創(chuàng)建登錄,登出,編輯和修改密碼的功能。你會學(xué)習(xí)如何為用戶創(chuàng)建自定義的個(gè)人資料,并在網(wǎng)站中添加社交認(rèn)證。

本章會涉及以下知識點(diǎn):

  • 使用認(rèn)證框架
  • 創(chuàng)建用戶注冊視圖
  • 用自定義個(gè)人資料模型擴(kuò)展User模型
  • python-social-auth添加社交認(rèn)證

讓我們從創(chuàng)建新項(xiàng)目開始。

4.1 創(chuàng)建一個(gè)社交網(wǎng)站項(xiàng)目

我們將會創(chuàng)建一個(gè)社交應(yīng)用,讓用戶可以分享他們在Internet上發(fā)現(xiàn)的圖片。我們需要為該項(xiàng)目構(gòu)建以下元素:

  • 一個(gè)認(rèn)證系統(tǒng),用于用戶注冊,登錄,編輯個(gè)人資料,修改或重置密碼
  • 一個(gè)關(guān)注系統(tǒng),允許用戶互相關(guān)注
  • 顯示分享的圖片,并實(shí)現(xiàn)一個(gè)書簽工具,讓用戶可以分享任何網(wǎng)站的圖片
  • 每個(gè)用戶的活動(dòng)信息,讓用戶可以看到他關(guān)注的用戶上傳的內(nèi)容

本章討論第一點(diǎn)。

4.1.1 啟動(dòng)社交網(wǎng)站項(xiàng)目

打開終端,使用以下命令為項(xiàng)目創(chuàng)建一個(gè)虛擬環(huán)境,并激活:

mkdir env
virtualenv env/bookmarks
source env/bookmarks/bin/activate

終端會如下顯示你激活的虛擬環(huán)境:

(bookmarks)laptop:~ zenx$

使用以下命令,在虛擬環(huán)境中安裝Django:

pip install Django

執(zhí)行以下命令創(chuàng)建一個(gè)新項(xiàng)目:

django-admin startproject bookmarks

創(chuàng)建初始項(xiàng)目結(jié)構(gòu)之后,使用以下命令進(jìn)入項(xiàng)目目錄,并創(chuàng)建一個(gè)account的新應(yīng)用:

cd bookmarks/
django-admin startapp account

通過把該應(yīng)用添加到settings.py文件的INSTALLED_APPS中,來激活它。把它放在INSTALLED_APPS列表的最前面:

INSTALLED_APPS = (
    'account',
    # ...
)

執(zhí)行下面的命令,同步INSTALLED_APPS設(shè)置中默認(rèn)應(yīng)用的模型到數(shù)據(jù)庫中:

python manage.py migrate

接下來,我們用authentication框架在項(xiàng)目中構(gòu)建一個(gè)認(rèn)證系統(tǒng)。

4.2 使用Django認(rèn)證框架

Django內(nèi)置一個(gè)認(rèn)證框架,可以處理用戶認(rèn)證,會話,權(quán)限和用戶組。該認(rèn)證系統(tǒng)包括常見的用戶操作視圖,比如登錄,登出,修改密碼和重置密碼。

認(rèn)證框架位于django.contrib.auth中,并且被其它Django contrib包使用。記住,你已經(jīng)在第一章中使用過認(rèn)證框架,為博客應(yīng)用創(chuàng)建了一個(gè)超級用戶,以便訪問管理站點(diǎn)。

當(dāng)你使用startproject命令創(chuàng)建新Django項(xiàng)目時(shí),認(rèn)證框架已經(jīng)包括在項(xiàng)目的默認(rèn)設(shè)置中。它由django.contrib.auth應(yīng)用和以下兩個(gè)中間件(middleware)類組成(這兩個(gè)中間類位于項(xiàng)目的MIDDLEWARE_CLASSES設(shè)置中):

  • AuthenticationMiddleware:使用會話管理用戶和請求
  • SessionMiddleware:跨請求處理當(dāng)前會話

一個(gè)中間件是一個(gè)帶有方法的類,在解析請求或響應(yīng)時(shí),這些方法在全局中執(zhí)行。你會在本書的好幾個(gè)地方使用中間件類。你會在第13章學(xué)習(xí)如何創(chuàng)建自定義的中間件。

該認(rèn)證框架還包括以下模塊:

  • User:一個(gè)有基礎(chǔ)字典的用戶模型;主要字段有:usernamepasswordemailfirst_namelast_nameis_active
  • Group:一個(gè)用于對用戶分類的組模型。
  • Permission:執(zhí)行特定操作的標(biāo)識。

該框架還包括默認(rèn)的認(rèn)證視圖和表單,我們之后會學(xué)習(xí)。

4.2.1 創(chuàng)建登錄視圖

我們從使用Django認(rèn)證框架允許用戶登錄網(wǎng)站開始。我們的視圖要執(zhí)行以下操作來登錄用戶:

  1. 通過提交表單獲得用戶名和密碼。
  2. 對比數(shù)據(jù)庫中的數(shù)據(jù),來驗(yàn)證用戶。
  3. 檢查用戶是否激活。
  4. 用戶登錄,并開始一個(gè)認(rèn)證的會話(authenticated session)。

首先,我們將創(chuàng)建一個(gè)登錄表單。在account應(yīng)用目錄中創(chuàng)建forms.py文件,添加以下代碼:

from django import forms

class LoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput)

該表單用于在數(shù)據(jù)庫用驗(yàn)證用戶。注意,我們使用PasswordInput組件來渲染包括type="password"屬性的HTML input元素。編輯account應(yīng)用的views.py文件,添加以下代碼:

from django.shortcuts import render
from django.http import HttpResponse
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})

這是我們在視圖中所做的基本登錄操作:當(dāng)使用GET請求調(diào)用user_login視圖時(shí),我們使用form = LoginForm()實(shí)例化一個(gè)新的登錄表單,用于在模板中顯示。當(dāng)用戶通過POST提交表單時(shí),我們執(zhí)行以下操作:

  1. 使用form = LoginForm(request.POST)實(shí)例化帶有提交的數(shù)據(jù)的表單。
  2. 檢查表單是否有效。如果無效,則在模板中顯示表單錯(cuò)誤(例如,用戶沒有填寫某個(gè)字段)。
  3. 如果提交的數(shù)據(jù)有效,我們使用authenticate()方法,在數(shù)據(jù)庫中驗(yàn)證用戶。該方法接收usernamepassword參數(shù),如果用戶驗(yàn)證成功,則返回User對象,否則返回None。如果用戶沒有通過驗(yàn)證,我們返回一個(gè)原始的HttpResponse,顯示一條消息。
  4. 如果用戶驗(yàn)證成功,我們通過is_active屬性檢查用戶是否激活。這是Django User模型的屬性。如果用戶沒有激活,我們返回一個(gè)HttpResponse顯示信息。
  5. 如果是激活的用戶,我們在網(wǎng)站登錄用戶。我們調(diào)用login()方法,把用戶設(shè)置在session中,并返回一條成功消息。

注意authenticatelogin之間的區(qū)別:authenticate()方法檢查用戶的認(rèn)證信息,如果正確,則返回User對象;login()在當(dāng)前session中設(shè)置用戶。

現(xiàn)在,你需要為該視圖創(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項(xiàng)目目錄中的urls.py文件,在其中包括account應(yīng)用的URL模式:

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^account/', include('account.urls')),
]

現(xiàn)在可以通過URL訪問登錄視圖了。是時(shí)候?yàn)樵撘晥D創(chuàng)建一個(gè)模板了。因?yàn)樵擁?xiàng)目還沒有模板,所以你可以創(chuàng)建一個(gè)基礎(chǔ)模板,在登錄模板中擴(kuò)展它。在account應(yīng)用目錄中創(chuàng)建以下文件和目錄:

templates/
    account/
        login.html
    base.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ǔ)模板。跟之前的項(xiàng)目一樣,我們在主模板中包括CSS樣式。該基礎(chǔ)模板定義了titlecontent區(qū)域,可以被從它擴(kuò)展的模板填充內(nèi)容。

讓我們?yōu)榈卿洷韱蝿?chuàng)建模板。打開account/login.html模板,添加以下代碼:

{% extends "base.html" %}

{% block title %}Log-in{% endblock  %}

{% block content %}
    <h1>Log-in</h1>
    <p>Please, user 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  %}

該模板包括了在視圖中實(shí)例化的表單。因?yàn)槲覀兊谋韱螘ㄟ^POST提交,所以我們使用{% csrf_token %}模板標(biāo)簽進(jìn)行CSRF保護(hù)。你在第2章學(xué)習(xí)了CSRF保護(hù)。

現(xiàn)在數(shù)據(jù)庫中還沒有用戶。首先,你需要?jiǎng)?chuàng)建一個(gè)超級用戶,訪問管理站點(diǎn)來管理其他用戶。打開命令行,執(zhí)行python manage.py createsuperuser。填寫必需的用戶名,郵箱和密碼。然后使用python manage.py runserver啟動(dòng)開發(fā)服務(wù)器,并在瀏覽器中打開http://127.0.0.1:8000/admin/。使用你剛創(chuàng)建的用戶登錄管理站點(diǎn)。你會看到Django管理站點(diǎn)中包括了Django認(rèn)證框架的UserGroup模型,如下圖所示:

通過管理站點(diǎn)創(chuàng)建一個(gè)新用戶,并在瀏覽器中打開http://127.0.0.1:8000/account/login/。你會看到包括登錄表單的模板:

現(xiàn)在,提交表單時(shí)不填其中一個(gè)字段。這時(shí),你會看到表單是無效的,并顯示錯(cuò)誤信息,如下圖所示:

如果你輸入一個(gè)不存在的用戶,或者錯(cuò)誤的密碼,你會看到一條Invalid login消息。

如果你輸入有效的認(rèn)證信息,會看到一條Authenticated successfully消息,如下圖所示:

4.2.2 使用Django認(rèn)證視圖

Django在認(rèn)證框架中包括了幾個(gè)表單和視圖,你可以直接使用。你已經(jīng)創(chuàng)建的登錄視圖對于理解Django中的用戶認(rèn)證過程是一個(gè)很好的練習(xí)。然而,你在絕大部分情況下可以使用默認(rèn)的Django認(rèn)證視圖。

Django提供了以下視圖處理認(rèn)證:

  • login:操作一個(gè)登錄表單,并登錄用戶
  • logout:登出一個(gè)用戶
  • logout_then_login:登出一個(gè)用戶,并重定向用戶到登錄頁面

Django提供以下視圖處理修改密碼:

  • password_change:操作一個(gè)修改用戶密碼的表單
  • password_change_done:修改密碼后,顯示成功頁面

Django還提供以下視圖用于重置密碼:

  • password_reset:允許用戶重置密碼。它生成一個(gè)帶令牌的一次性鏈接,并發(fā)送到用戶的電子郵箱中。
  • password_reset_done:告訴用戶,重置密碼的郵件已經(jīng)發(fā)送到他的郵箱中。
  • password_reset_confirm:讓用戶設(shè)置新密碼。
  • password_reset_complete:用戶重置密碼后,顯示成功頁面。

創(chuàng)建一個(gè)帶用戶賬戶的網(wǎng)站時(shí),這里列出的視圖會節(jié)省你很多時(shí)間。你可以覆蓋這些視圖使用的默認(rèn)值,比如需要渲染的模板的位置,或者視圖使用的表單。

你可以在這里獲得更多關(guān)于內(nèi)置的認(rèn)證視圖的信息。

4.2.3 登錄和登出視圖

編輯account應(yīng)用的urls.py文件,如下所示:

from django.conf.urls import url
from django.contrib.auth.views import login, logout, logout_then_login
from . import views

urlpatterns = [
    # previous login view
    # url(r'^login/$', views.user_login, name='login'),

    # login / logout urls
    url(r'^login/$', login, name='login'),
    url(r'^logout/$', logout, name='logout'),
    url(r'^logout-then-login/$', logout_then_login, name='logout_then_login'),
]

譯者注:Django新版本中,URL模式使用方式跟舊版本不一樣。

我們注釋了之前為user_login視圖創(chuàng)建的URL模式,使用了Django認(rèn)證框架的login視圖。

account應(yīng)用的templates目錄中創(chuàng)建一個(gè)registration目錄。這是Django認(rèn)證視圖的默認(rèn)路徑,它期望你的認(rèn)證模板在這個(gè)路徑下。在新創(chuàng)建的目錄中創(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, user 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  %}

這個(gè)login模板跟我們之前創(chuàng)建那個(gè)很像。Django默認(rèn)使用django.contrib.auth.forms中的AuthenticationForm。該表單嘗試驗(yàn)證用戶,如果登錄不成功,則拋出一個(gè)驗(yàn)證錯(cuò)誤。這種情況下,如果認(rèn)證信息出錯(cuò),我們可以在模板中使用{% if form.errors %}查找錯(cuò)誤。注意,我們添加了一個(gè)隱藏的HTML <input>元素,用于提交名為next的變量的值。當(dāng)你在請求中傳遞一個(gè)next參數(shù)時(shí)(比如,http://127.0.0.1:8000/account/login/?next=/account/),這個(gè)變量首次被登錄視圖設(shè)置。

next參數(shù)必須是一個(gè)URL。如果指定了這個(gè)參數(shù),Django登錄視圖會在用戶登錄后,重定義到給定的URL。

現(xiàn)在,在registration模板目錄中創(chuàng)建一個(gè)logged_out.html模板,添加以下代碼:

{% 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  %}

用戶登出之后,Django會顯示這個(gè)模板。

為登錄和登出視圖添加URL模式和模板后,網(wǎng)站已經(jīng)可以使用Django認(rèn)證視圖登錄了。

注意,我們在urlconf中包含的logout_then_login視圖不需要任何模板,因?yàn)樗囟x到了登錄視圖。

現(xiàn)在我們開始創(chuàng)建一個(gè)新的視圖,當(dāng)用戶登錄賬號時(shí),用于顯示用戶的儀表盤。打開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)證框架的login_required裝飾器裝飾視圖。該裝飾器檢查當(dāng)前用戶是否認(rèn)證。如果是認(rèn)證用戶,它會執(zhí)行被裝飾的視圖。如果不是認(rèn)證用戶,它會重定向用戶到登錄URL,并在登錄URL中帶上一個(gè)名為nextGET參數(shù),該參數(shù)是用戶試圖訪問的URL。通過這樣的做法,當(dāng)用戶成功登錄后,登錄視圖會重定向用戶到用戶登錄之前試圖訪問的頁面。記住,我們在登錄模板的表單中添加了一個(gè)隱藏的<input>元素就是為了這個(gè)目的。

我們還定義了一個(gè)section變量。我們用這個(gè)變量跟蹤用戶正在查看網(wǎng)站的哪一部分(section)。多個(gè)視圖可能對應(yīng)相同的部分。這是定義每個(gè)視圖對應(yīng)的section的簡便方式。

現(xiàn)在,你需要為儀表盤視圖創(chuàng)建一個(gè)模板。在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  %}

接著,在account應(yīng)用的urls.py文件中,為該視圖添加URL模式:

urlpatterns = [
    # ...
    url(r'^$', views.dashboard, name='dashboard'),
 ]

編輯項(xiàng)目的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視圖沒有獲得next參數(shù)時(shí),登錄后重定向到哪個(gè)URL
  • LOGIN_URL:重定向用戶登錄的URL(比如使用login_required裝飾器)
  • LOGOUT_URL:重定向用戶登出的URL

我們使用reverse_lazy(),通過URL的名字動(dòng)態(tài)創(chuàng)建URL。reverse_lazy()函數(shù)跟reverse()函數(shù)一樣逆向URL。當(dāng)你需要在項(xiàng)目URL配置加載之前逆向URL時(shí),可以使用reverse_lazy()

讓我們總結(jié)一下,到現(xiàn)在為止,我們做了哪些工作:

  • 你在項(xiàng)目中添加了內(nèi)置的Django認(rèn)證登錄和登出視圖
  • 你為這兩個(gè)視圖創(chuàng)建了自定義模板,并定義了一個(gè)簡單的視圖,讓用戶登錄后重定向到這個(gè)視圖
  • 最后,你配置了設(shè)置,讓Django默認(rèn)使用這些URL

現(xiàn)在,我們需要把登錄和登出鏈接到基礎(chǔ)模板中,把所有功能串起來。

要做到這點(diǎn),我們需要確定,無論當(dāng)前用戶是否登錄,都能顯示適當(dāng)?shù)逆溄印Mㄟ^認(rèn)證中間件,當(dāng)前用戶被設(shè)置在HttpRequest對象中。你可以通過request.user訪問。即使用戶沒有認(rèn)證,你也可以找到一個(gè)用戶對象。一個(gè)未認(rèn)證的用戶在request中是一個(gè)AnonymousUser的實(shí)例。調(diào)用request.user.is_authenticated()是檢測當(dāng)前用戶是否認(rèn)證最好的方式。

編輯base.html文件,修改ID為header<div>,如下所示:

<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>

正如你所看到的,我們只為認(rèn)證的用戶顯示網(wǎng)站的菜單。我們還檢查當(dāng)前的section,通過CSS為相應(yīng)的<li>項(xiàng)添加selected類屬性來高亮顯示菜單中的當(dāng)前section。我們還顯示用戶的姓,如果是認(rèn)證過的用戶,還顯示一個(gè)登出鏈接,否則顯示登錄鏈接。

現(xiàn)在,在瀏覽器中打開http://127.0.0.1:8000/account/login。你會看到登錄頁面。輸入有效的用戶名和密碼,點(diǎn)擊Log-in按鈕,你會看到這樣的頁面:

因?yàn)?code>My dashboard有selected屬性,所以你會看到它是高亮顯示的。因?yàn)槭钦J(rèn)證過的用戶,所以用戶的姓顯示在頭部的右邊。點(diǎn)擊Logout鏈接,你會看到下面的頁面:

在這個(gè)頁面中,用戶已經(jīng)登出,所以你不能再看到網(wǎng)站的菜單。現(xiàn)在頭部右邊顯示Log-in鏈接。

如果你看到的是Django管理站點(diǎn)的登出頁面,而不是你自己的登出頁面,檢查項(xiàng)目的INSTALLED_APPS設(shè)置,確保django.contrib.adminaccount應(yīng)用之后。這兩個(gè)模板位于同樣的相對路徑中,Django目錄加載器會使用第一個(gè)。

4.2.4 修改密碼視圖

用戶登錄我們的網(wǎng)站后,我們需要用戶可以修改他們的密碼。我們通過集成Django認(rèn)證視圖來修改密碼。打開account應(yīng)用的urls.py文件,添加以下URL模式:

from django.contrib.auth.views import password_change
from django.contrib.auth.views import password_change_done

# change password urls
urlpatterns = [
    url(r'^password-change/$', password_change, name='password_change'),
    url(r'^password_change/done/$', password_change_done, name='password_change_done'),
]

password_change視圖會處理修改密碼表單,password_change_done會在用戶成功修改密碼后顯示一條成功消息。讓我們?yōu)槊總€(gè)視圖創(chuàng)建一個(gè)模板。

account應(yīng)用的templates/registration/目錄中創(chuàng)建password_change_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 %}

該模板包括修改密碼的表單。在同一個(gè)目錄下創(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 %}

該模板只包括一條用戶成功修改密碼后顯示的成功消息。

在瀏覽器中打開http://127.0.0.1:8000/account/password-change/。如果用戶沒有登錄,瀏覽器會重定向到登錄頁面。當(dāng)你認(rèn)證成功后,你會看到下面的修改密碼頁面:

在表單中填寫當(dāng)前密碼和新密碼,點(diǎn)擊Change按鈕。你會看到以下成功頁面:

登出后,使用新密碼再次登錄,確定所有功能都能正常工作。

4.2.5 重置密碼視圖

account應(yīng)用的urls.py文件中,為重置密碼添加以下URL模式:

from django.contrib.auth.views import password_reset
from django.contrib.auth.views import password_reset_done
from django.contrib.auth.views import password_rest_confirm
from django.contrib.auth.views import password_reset_complete

# restore password urls
url(r'^password-reset/$', password_reset, name='password_reset'),
url(r'^password-reset/done/$', password_reset_done, name='password_reset_done'),
url(r'^password-reset/confirm/(?P<uidb64>[-\w]+)/(?P<token>[-\w]+)/$', password_reset_confirm, name='password_reset_confirm'),
url(r'^password-reset/complete/$', password_reset_complete, name='password_reset_complete'),

account應(yīng)用的templates/registration/目錄中創(chuàng)建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 %}

在同一個(gè)目錄下創(chuàng)建password_reset_email.html文件,添加以下代碼:

Someon asked for password reset for email {{ email }}. Fllow the link below:
{{ protocol }}://{{ domain }}/{% url "password_reset_form" uidb64=uid token=token %}
Your usernmae, in case you've forgotten: {{ user.get_username }}

這個(gè)模板用于渲染發(fā)送給用戶重置密碼的郵件。

在同一個(gè)目錄下創(chuàng)建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)建另一個(gè)模板文件password_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">
            {{ formo.as_p }}
            {% csrf_token %}
            <p><input type="submit" value="Change my password" /></p>
        </form>
    {% else %}
        <p>The password reset link was invalid, possible because it has already been used. 
            Please request a new password reset.</p>
    {% endif %}
{% endblock  %}

我們檢查提供的鏈接是否有效。Django重置頁面視圖設(shè)置該變量,并把它放在這個(gè)模板的上下文中。如果鏈接有效,我們顯示重置密碼表單。

創(chuàng)建另一個(gè)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模板,在<form>元素后面添加以下代碼:

<p><a href="{% url "password_reset" %}">Forgotten your password?</a></p>

現(xiàn)在,在瀏覽器中打開htth://127.0.0.1:8000/account/login/,點(diǎn)擊Forgotten your password?鏈接,你會看到以下鏈接:

此時(shí),你需要在項(xiàng)目的settings.py文件中添加SMTP配置,讓Django可以發(fā)送郵件。我們已經(jīng)在第二章學(xué)習(xí)了如何添加郵件設(shè)置。但是在開發(fā)期間,你可以讓Django在標(biāo)準(zhǔn)輸出中寫郵件,代替通過SMTP服務(wù)發(fā)送郵件。Django提供了一個(gè)郵件后臺,可以把郵件輸出到控制臺。編輯項(xiàng)目的settings.py文件,添加下面這一行代碼:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

EMAIL_BACKEND設(shè)置指定用于發(fā)送郵件的類。

回到瀏覽器,輸入已有用戶的郵箱地址,點(diǎn)擊Send a e-mail按鈕。你會看到以下頁面:

看一眼正在運(yùn)行開發(fā)服務(wù)器的控制臺,你會看到生成的郵件:

MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Password reset on 127.0.0.1:8000
From: webmaster@localhost
To: lakerszhy@gmail.com
Date: Tue, 02 May 2017 03:50:20 -0000
Message-ID: <20170502035020.7440.93778@bogon>

Someon asked for password reset for email lakerszhy@gmail.com. Fllow the link below:
http://127.0.0.1:8000/account/password-reset/confirm/Mg/4lp-4b14906c833231658e9f/
Your usernmae, in case you've forgotten: antonio

郵件使用我們之間創(chuàng)建的password_reset_email.html模板渲染。重置密碼的URL包括一個(gè)Django動(dòng)態(tài)生成的令牌。在瀏覽器中打開連接,會看到以下頁面:

設(shè)置新密碼的頁面對應(yīng)password_reset_confirm.html模板。填寫新密碼并點(diǎn)擊Change my password按鈕。Django會創(chuàng)建一個(gè)新的加密密碼,并保存到數(shù)據(jù)庫中。你會看到一個(gè)成功頁面:

現(xiàn)在你可以使用新密碼再次登錄。每個(gè)用于設(shè)置新密碼的令牌只能使用一次。如果你再次打開收到的鏈接,會看到一條令牌無效的消息。

你已經(jīng)在項(xiàng)目中集成了Django認(rèn)證框架的視圖。這些視圖適用于大部分場景。如果需要不同的行為,你可以創(chuàng)建自己的視圖。

4.3 用戶注冊和用戶資料

現(xiàn)在,已存在的用戶可以登錄,登出和修改密碼,如果用戶忘記密碼,可以重置密碼。現(xiàn)在,我們需要?jiǎng)?chuàng)建視圖,用于游客創(chuàng)建賬戶。

4.3.1 用戶注冊

讓我們創(chuàng)建一個(gè)簡單的視圖,允許用戶在我們的網(wǎng)站注冊。首先,我們必須創(chuàng)建一個(gè)表單,讓用戶輸入用戶名,姓名和密碼。編輯account應(yīng)用中的forms.py文件,添加以下代碼:

from django.contrib.auth.models import User

class UserRegistrationForm(forms.ModelForm):
    password = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('username', 'first_name', 'email')

    def clean_password2(self):
        cd = self.cleaned_data
        if cd['password'] != cd['password2']:
            raise forms.ValidationError("Passwords don't match.")
        return cd['password2']

我們?yōu)?code>User模型創(chuàng)建了一個(gè)模型表單。在表單中,我們只包括了模型的usernamefirst_nameemail字段。這些字段會根據(jù)相應(yīng)的模型字段驗(yàn)證。例如,如果用戶選擇了一個(gè)已存在的用戶名,會得到一個(gè)驗(yàn)證錯(cuò)誤。我們添加了兩個(gè)額外字段:passwordpassword2,用來設(shè)置密碼和確認(rèn)密碼。我們定義了clean_password2()方法,檢查兩次輸入的密碼是否一致,如果不一致,則讓表單無效。當(dāng)我們調(diào)用表單的is_valid()方法驗(yàn)證時(shí),這個(gè)檢查會執(zhí)行。你可以為任何表單字段提供clean_<fieldname>()方法,清理特定字段的值或拋出表單驗(yàn)證錯(cuò)誤。表單還包括一個(gè)通用的clean()方法驗(yàn)證整個(gè)表單,驗(yàn)證相互依賴的字段時(shí)非常有用。

Django還在django.contrib.auth.forms中提供了UserCreationForm表單供你使用,這個(gè)表單跟我們剛創(chuàng)建的表單類似。

編輯account應(yīng)用中的views.py文件,添加以下代碼:

from .forms import LoginForm, UserRegistrationForm

def register(request):
    if request.method == 'POST':
        user_form = UserRegistrationForm(request.POST)
        if user_form.is_valid():
            # Create a new user object but avoid saving it yet
            new_user = user_form.save(commit=False)
            # Set the chosen password
            new_user.set_password(user_form.cleaned_data['password'])
            # Save the User object
            new_user.save()
            return render(request, 'account/register_done.html', {'new_user': new_user})
    else:
        user_form = UserRegistrationForm()
    return render(request, 'account/register.html', {'user_form': user_form})

這個(gè)創(chuàng)建用戶賬戶的視圖非常簡單。為了安全,我們使用User模型的set_password()方法處理加密保存,來代替保存用戶輸入的原始密碼。

現(xiàn)在編輯account應(yīng)用的urls.py文件,添加以下URL模式:

url(r'^register/$', views.register, name='register')

最后,我們在account/模板目錄中創(chuàng)建register.html文件,添加以下代碼:

{% extends "base.html" %}

{% block title %}Create an account{% endblock %}

{% block content %}
    <h1>Create an account</h1>
    <p>Please, sign up using the following form:</p>
    <form action="." method="post">
        {{ user_form.as_p }}
        {% csrf_token %}
        <p><input type="submit" value="Create my account"></p>
    </form>
{% endblock %}

在同一個(gè)目錄中添加register_done.html模板文件,添加以下代碼:

{% extends "base.html" %}

{% block title %}Welcome{% endblock %}

{% block content %}
    <h1>Welcome {{ new_user.first_name }}!</h1>
    <p>Your account has been successfully created. Now you can <a href="{% url "login" %}">log in</a>.</p>
{% endblock %}

現(xiàn)在,在瀏覽器中打開http://127.0.0.1:8000/account/register/,你會看到剛創(chuàng)建的注冊頁面:

為新用戶填寫信息,點(diǎn)擊Create my account按鈕。如果所有字段都有效,則會創(chuàng)建用戶,你會看到下面的成功消息:

點(diǎn)擊log in鏈接,輸入你的用戶名和密碼驗(yàn)證能否訪問你的賬戶。

現(xiàn)在,你還可以在登錄模板中添加注冊鏈接。編輯registration/login.html模板,把這行代碼:

<p>Please, user the following form to log-in</p>

替換為:

<p>Please, user the following form to log-in. 
If you don't have an account <a href="{% url "register" %}">register here</a></p>

我們可以通過登錄頁面訪問注冊頁面了。

4.3.2 擴(kuò)展User模型

當(dāng)你必須處理用戶賬戶時(shí),你會發(fā)現(xiàn)Django認(rèn)證框架的User模型適用于常見情況。但是User模型有非常基礎(chǔ)的字段。你可能希望擴(kuò)展User模型包含額外的數(shù)據(jù)。最好的方式是創(chuàng)建一個(gè)包括所有額外字段的個(gè)人資料模型,并且與Django的User模型是一對一的關(guān)系。

編輯account應(yīng)用的models.py文件,添加以下代碼:

from django.db import models
from django.conf import settings

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    date_of_birth = models.DateField(blank=True, null=True)
    photo = models.ImageField(upload_to='users/%Y/%m/%d', blank=True)

    def __str__(self):
        return 'Pofile for User {}'.format(self.user.username)

為了讓代碼保持通用性,請使用get_user_model()方法檢索用戶模型。同時(shí),定義模型和用戶模型之間的關(guān)系時(shí),使用AUTH_USER_MODEL設(shè)置引用用戶模型,而不是直接引用該用戶模型。

一對一的user字段允許我們用用戶關(guān)聯(lián)個(gè)人資料。photo字段是一個(gè)ImageField字段。你需要安裝PIL(Python Imaging Library)或Pillow(PIL的一個(gè)分支)Python包來管理圖片。在終端中執(zhí)行以下命令安裝Pillow:

pip install Pillow

為了在Django開發(fā)服務(wù)器中提供多媒體文件上傳功能,需要在項(xiàng)目的settings.py文件中添加以下設(shè)置:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

MEDIA_URL是用戶上傳的多媒體文件的基URL,MEDIA_ROOT是多媒體文件的本地路徑。我們根據(jù)項(xiàng)目路徑動(dòng)態(tài)構(gòu)建該路徑,讓代碼更通用。

現(xiàn)在,編輯bookmarks項(xiàng)目的主urls.py文件,如下所示修改代碼:

from django.conf import settings
from django.conf.urls.static import static

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

這樣,Django開發(fā)服務(wù)器將在開發(fā)過程中負(fù)責(zé)多媒體文件服務(wù)。

static()幫助函數(shù)只適用于開發(fā)環(huán)境,不適合生產(chǎn)環(huán)境。永遠(yuǎn)不要在生產(chǎn)環(huán)境使用Django為靜態(tài)文件提供服務(wù)。

打開終端執(zhí)行以下命令,為新模型創(chuàng)建數(shù)據(jù)庫遷移:

python manage.py makemigrations

你會得到這樣的輸出:

Migrations for 'account':
  account/migrations/0001_initial.py
    - Create model Profile

接著使用以下命令同步數(shù)據(jù)庫:

python manage.py migrate

你會看到包括下面這一樣的輸出:

Applying account.0001_initial... OK

編輯account應(yīng)用的admin.py文件,在管理站點(diǎn)注冊Profile模型,如下所示:

from .models import Profile

class ProfileAdmin(admin.ModelAdmin):
    list_display = ('user', 'date_of_birth', 'photo')

admin.site.register(Profile, ProfileAdmin)

使用python manage.py runserver命令運(yùn)行開發(fā)服務(wù)器。現(xiàn)在,你會在項(xiàng)目的管理站點(diǎn)看到Profile模型,如下圖所示:

現(xiàn)在,我們將讓用戶在網(wǎng)站上編輯個(gè)人資料。在account應(yīng)用的forms.py文件中添加以下模型表單:

from .models import Profile

class UserEditForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

class ProfileEditForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('date_of_birth', 'photo')

這些表單的作用是:

  • UserEditForm:允許用戶編輯存在內(nèi)置的User模型中的姓,名和郵箱。
  • ProfileEditForm:允許用戶編輯存在自定義的Profile模型中的額外數(shù)據(jù)。用戶可以編輯出生日期,并上傳一張圖片。

編輯account應(yīng)用的views.py文件,導(dǎo)入Profile模型:

from .models import Profile

register視圖的new_user.save()下面添加以下代碼:

# Create the user profile
profile = Profile.objects.create(user=new_user)

當(dāng)用戶在我們網(wǎng)站注冊時(shí),我們會創(chuàng)建一個(gè)空的個(gè)人資料關(guān)聯(lián)到用戶。你需要使用管理站點(diǎn)手動(dòng)為之前創(chuàng)建的用戶創(chuàng)建Profile對象。

現(xiàn)在我們讓用戶可以編輯個(gè)人資料。添加以下代碼到同一個(gè)文件中:

from .forms import LoginForm, UserRegistrationForm, UserEditForm, ProfileEditForm

@login_required
def edit(request):
    if request.method == 'POST':
        user_form = UserEditForm(instance=request.user, data=request.POST)
        profile_form = ProfileEditForm(instance=request.user.profile, 
                                       data=request.POST,
                                       files=request.FILES)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
    else:
        user_form = UserEditForm(instance=request.user)
        profile_form = ProfileEditForm(instance=request.user.profile)

    return render(request, 'account/edit.html', {'user_form': user_form, 'profile_form': profile_form})

我們使用了login_required裝飾器,因?yàn)橛脩舯仨氄J(rèn)證后才能編輯個(gè)人資料。在這里,我們使用了兩個(gè)模型表單:UserEditForm存儲內(nèi)置的User模型數(shù)據(jù),ProfileEditForm存儲額外的個(gè)人數(shù)據(jù)。我們檢查兩個(gè)表單的is_valid()方法返回True來驗(yàn)證提交的數(shù)據(jù)。在這里,我們保持兩個(gè)表單,用來更新數(shù)據(jù)庫中相應(yīng)的對象。

account應(yīng)用的urls.py文件中添加以下URL模式:

url(r'^edit/$', views.edit, name='edit')

最后,在templates/account/目錄中,為該視圖創(chuàng)建edit.html模板,添加以下代碼:

{% extends "base.html" %}

{% block title %}Edit your account{% endblock %}

{% block content %}
    <h1>Edit your account</h1>
    <p>You can edit your account using the following form:</p>
    <form action="." method='post' enctype="multipart/form-data">
        {{ user_form.as_p }}
        {{ profile_form.as_p }}
        {% csrf_token %}
        <p><input type="submit" value="Save changes"></p>
    </form>
{% endblock %}

我們在表單中包括了enctype="multipart/form-data",來啟用文件上傳。我們使用一個(gè)HTML表單提交user_formprofile_form兩個(gè)表單。

注冊一個(gè)新用戶,并在瀏覽器中打開http://127.0.0.1:8000/account/edit/,你會看到以下界面:

現(xiàn)在你可以編輯儀表盤頁面,來包括編輯個(gè)人資料和修改密碼的頁面鏈接。打開account/dashboard.html模板,把這一行代碼:

<p>Welcome to your dashboard.</p>

替換為:

<p>
    Welcome to your dashboard. 
    You can <a href="{% url "edit" %}">edit your profiles</a> 
    or <a href="{% url "password_change" %}">change your password</a>. 
</p>

用戶現(xiàn)在可以通過儀表盤訪問編輯個(gè)人資料的表單。

4.3.2.1 使用自定義User模型

Django還提供了方式,可以用自定義模型代替整個(gè)User模型。你的用戶類應(yīng)從Django的AbstractUser類繼承,它作為一個(gè)抽象模型,提供了默認(rèn)用戶的完整實(shí)現(xiàn)。你可以在這里閱讀更多關(guān)于這個(gè)模型的信息。

使用自定義用戶模型會有更多的靈活性,但它也可能給一些需要與User模型交互的可插拔應(yīng)用應(yīng)用的集成帶來一定的困難。

4.3.3 使用消息框架

處理用戶動(dòng)作時(shí),你可能想要通知用戶動(dòng)作的結(jié)果。Django內(nèi)置一個(gè)消息框架,允許你顯示一次性提示。該消息框架位于django.contrib.message中,當(dāng)你用python manage.py startproject創(chuàng)建新項(xiàng)目時(shí),它默認(rèn)包括在settings.pyINSTALLED_APPS列表中。你注意到,設(shè)置文件的MIDDLEWARE_CLASSES設(shè)置列表中,包括一個(gè)名為django.contrib.message.middleware.MessageMiddleware的中間件。該消息框架提供了一種簡單的方式來給用戶添加消息。消息存儲在數(shù)據(jù)庫中,并會在用戶下次請求時(shí)顯示。你可以通過導(dǎo)入消息模塊,使用簡單的快捷方式添加新消息,來在視圖中使用消息框架,如下所示:

from django.contrib import message
message.error(request, 'Something went wrong')

你可以使用add_message()方法,或者以下任何一個(gè)快捷方法創(chuàng)建新消息:

  • success():動(dòng)作執(zhí)行成功后顯示成功消息
  • info():信息消息
  • waring():還沒有失敗,但很可能馬上失敗
  • error():一個(gè)不成功的操作,或某些事情失敗
  • debug():調(diào)試信息,會在生產(chǎn)環(huán)境移除或忽略

讓我們顯示消息給用戶。因?yàn)橄⒖蚣軐?xiàng)目來說是全局的,所以我們可以在基礎(chǔ)模板中顯示消息給用戶。打開base.html模板,在id為header和content的<div>元素之間添加以下代碼:

{% if messages %}
    <ul class="messages">
        {% for message in messages %}
            <li class="{{ message.tags }}">
                {{ message|safe }}
                <a href="#" class="close">?</a>
            </li>
        {% endfor %}
    </ul>
{% endif %}

消息框架包括一個(gè)上下文處理器(context processor),它會添加messages變量到請求上下文中。因此,你可以在模板使用該變量顯示當(dāng)前消息。

現(xiàn)在,讓我們修改edit視圖來使用消息框架。編輯account應(yīng)用的views.py文件,如下修改edit視圖:

from django.contrib import messages

@login_required
def edit(request):
    if request.method == 'POST':
    # ...
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, 'Profile updated successfully')
        else:
            messages.error(request, 'Error updating your profile')
    else:
        user_form = UserEditForm(instance=request.user)
        # ...

當(dāng)用戶成功更新個(gè)人資料后,我們添加一條成功消息。如果任何一個(gè)表單無效,我們添加一條錯(cuò)誤消息。

在瀏覽器中打開http://127.0.0.1:8000/account/edit/,并編輯你的個(gè)人資料。當(dāng)個(gè)人資料更新成功后,你會看到以下消息:

當(dāng)表單無效時(shí),你會看到以下消息:

4.4 創(chuàng)建自定義認(rèn)證后臺

Django允許你針對不同來源進(jìn)行身份驗(yàn)證。AUTHENTICATION_BACKENDS設(shè)置包括了項(xiàng)目的認(rèn)證后臺列表。默認(rèn)情況下,該設(shè)置為:

('django.contrib.auth.backends.ModelBackend',)

默認(rèn)的ModelBackend使用django.contrib.authUser模型,驗(yàn)證數(shù)據(jù)庫中的用戶。這適用于大部分項(xiàng)目。但是你可以創(chuàng)建自定義的后臺,來驗(yàn)證其它來源的用戶,比如一個(gè)LDAP目錄或者其它系統(tǒng)。

你可以在這里閱讀更多關(guān)于自定義認(rèn)證的信息。

一旦你使用django.contrib.auth中的authenticate()函數(shù),Django會一個(gè)接一個(gè)嘗試AUTHENTICATION_BACKENDS中定義的每一個(gè)后臺來驗(yàn)證用戶,直到其中一個(gè)驗(yàn)證成功。只有所有后臺都驗(yàn)證失敗,才不會在站點(diǎn)中驗(yàn)證通過。

Django提供了一種簡單的方式來定義自己的認(rèn)證后臺。一個(gè)認(rèn)證后臺是提供了以下兩個(gè)方法的類:

  • authenticate():接收用戶信息作為參數(shù),如果用戶認(rèn)證成功,則返回True,否則返回False。
  • get_user():接收用戶ID作為參數(shù),并返回一個(gè)User對象。

創(chuàng)建一個(gè)自定義認(rèn)證后臺跟編寫一個(gè)實(shí)現(xiàn)這兩個(gè)方法的Python類一樣簡單。我們會創(chuàng)建一個(gè)認(rèn)證后臺,讓用戶使用郵箱地址代替用戶名驗(yàn)證。

account應(yīng)用目錄中創(chuàng)建一個(gè)authentication.py文件,添加以下代碼:

from django.contrib.auth.models import User

class EmailAuthBackend:
    """
    Authenticates using e-mail account.
    """
    def authenticate(self, username=None, password=None):
        try:
            user = User.objects.get(email=username)
            if user.check_password(password):
                return user
            return None
        except User.DoesNotExist:
            retur None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

這是一個(gè)很簡單的認(rèn)證后臺。authenticate()方法接收usernamepassword作為可選參數(shù)。我們可以使用不同的參數(shù),但我們使用usernamepassword確保后臺可以立即在認(rèn)證框架中工作。上面的代碼完成以下工作:

  • authenticate():我們嘗試使用給定的郵箱地址檢索用戶,并用User模型內(nèi)置的check_password()方法檢查密碼。該方法會處理密碼哈希化,并比較給定的密碼和數(shù)據(jù)庫中存儲的密碼。
  • get_user():我們通過user_id參數(shù)獲得一個(gè)用戶。在用戶會話期間,Django使用認(rèn)證用戶的后臺來檢索User對象。

編輯項(xiàng)目的settings.py,添加以下設(shè)置:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'account.authentication.EmailAuthBackend',
)

我們保留了默認(rèn)的ModelBackend,使用用戶名和密碼認(rèn)證,并包括了自己的基于郵箱地址的認(rèn)證后臺。現(xiàn)在,在瀏覽器中打開http://127.0.0.1/8000/account/login/。記住,Django會試圖使用每一個(gè)后臺驗(yàn)證用戶,所以你現(xiàn)在可以使用用戶名或郵箱賬號登錄。

AUTHENTICATION_ BACKENDS設(shè)置中列出的后端順序很重要。如果同樣的信息對于多個(gè)后臺都有效,Django會在第一個(gè)成功驗(yàn)證用戶的后臺停止。

4.5 為網(wǎng)站添加社交認(rèn)證

你可能還想為網(wǎng)站添加社交認(rèn)證,比如使用Facebook,Twitter或Google服務(wù)認(rèn)證。Python-socail-auth是一個(gè)Python模塊,可以簡化添加社交認(rèn)證過程。通過這個(gè)模塊,你可以讓用戶使用其他服務(wù)的賬戶登錄你的網(wǎng)站。

譯者注:從2016年12月3日開始,這個(gè)模塊遷移到了Python Social Auth。原書的內(nèi)容已經(jīng)過時(shí),所以就不翻譯了。

4.6 總結(jié)

在本章中,你學(xué)習(xí)了如何在網(wǎng)站中構(gòu)建認(rèn)證系統(tǒng)和創(chuàng)建自定義用戶資料。你還在網(wǎng)站中添加了社交認(rèn)證。

下一章中,你會學(xué)習(xí)如何創(chuàng)建一個(gè)圖片書簽系統(tǒng),生成圖片的縮略圖,以及創(chuàng)建AJAX視圖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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