《Django By Example》第四章 中文 翻譯 (我的學習,渣翻)

書籍出處:https://www.packtpub.com/web-development/django-example
原做者:Antonio Melécss

2017年1月4日初稿發佈html

2017年5月5日第一次精校完成(感謝大牛 @kukoo 的精校!)python

(譯者注:祝你們新年快樂,此次帶來《Django By Example》第四章的翻譯,這章很是的實用,就這樣)git

第四章

建立一個社交網站

在上一章中,你學習瞭如何建立站點地圖(sitemaps)和feeds,你還爲你的blog應用建立了一個搜索引擎。在本章中,你將開發一個社交應用。你會爲用戶建立一些功能,例如:登陸,登出,編輯,以及重置他們的密碼。你會學習如何爲你的用戶建立一個定製的profile,你還會爲你的站點添加社交認證。github

本章將會覆蓋一下幾點:web

  • 使用認證(authentication)框架
  • 建立用戶註冊視圖(views)
  • 經過一個定製的profile模型(model)擴展User模型(model)
  • 使用python-social-auth添加社交認證

讓咱們開始建立咱們的新項目吧。shell

建立一個社交網站項目

咱們要建立一個社交應用容許用戶分享他們在網上找到的圖片。咱們須要爲這個項目構建如下元素:數據庫

  • 一個用來給用戶註冊,登陸,編輯他們的profile,以及改變或重置密碼的認證(authentication)系統
  • 一個容許用戶來關注其餘人的關注系統(這裏原文是follow,‘跟隨’,感受用‘關注’更加適合點)
  • 爲用戶從其餘任何網站分享過來的圖片進行展現和打上書籤
  • 每一個用戶都有一個活動流容許他們看到所關注的人上傳的內容

本章主要講述第一點。django

開始你的社交網站項目

打開終端使用以下命令行爲你的項目建立一個虛擬環境而且激活它:

mkdir evn
virtualenv evn/bookmarks
source env/bookmarks/bin/activate後端

shell提示將會展現你激活的虛擬環境,以下所示:

(bookmarks)laptop:~ zenx$

經過如下命令在你的虛擬環境中安裝Django:

pip install Django==1.8.6

運行如下命令來建立一個新項目:

django-admin startproject bookmarks

在建立好一個初始的項目結構之後,使用如下命令進入你的項目目錄而且建立一個新的應用命名爲account:

cd bookmarks/
django-admin startapp account

請記住在你的項目中激活一個新應用須要在settings.py文件中的INSTALLED_APPS設置中添加它。將新應用的名字添加在INSTALLED_APPS列中的全部已安裝應用的最前面,以下所示:

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

運行下一條命令爲INSTALLED_APPS中默認包含的應用模型(models)同步到數據庫中:

python manage.py migrate

咱們將要使用認證(authentication)框架來構建一個認證系統到咱們的項目中。

使用Django認證(authentication)框架

Django擁有一個內置的認證(authentication)框架用來操做用戶認證(authentication),會話(sessions),權限(permissions)以及用戶組。這個認證(authentication)系統包含了一些普通用戶的操做視圖(views),例如:登陸,登出,修改密碼以及重置密碼。

這個認證(authentication)框架位於django.contrib.auth,被其餘Django的contrib包調用。請記住你在第一章 建立一個Blog應用中使用過這個認證(authentication)框架並用來爲你的blog應用建立了一個超級用戶來使用管理站點。

當你使用startproject命令建立一個新的Django項目,認證(authentication)框架已經在你的項目設置中默認包含。它是由django.contrib.auth應用和你的項目設置中的MIDDLEWARE_CLASSES中的兩個中間件類組成,以下:

  • AuthenticationMiddleware:使用會話(sessions)將用戶和請求(requests)進行關聯
  • SessionMiddleware:經過請求(requests)操做當前會話(sessions)

中間件就是一個在請求和響應階段帶有全局執行方法的類。你會在本書中的不少場景中使用到中間件。你將會在第十三章 Going Live中學習如何建立一個定製的中間件(譯者注:啥時候能翻譯到啊)。

這個認證(authentication)系統還包含了如下模型(models):

  • User:一個包含了基礎字段的用戶模型(model);這個模型(model)的主要字段有:username, password, email, first_name, last_name, is_active。
  • Group:一個組模型(model)用來分類用戶
  • Permission:執行特定操做的標識

這個框架還包含默認的認證(authentication)視圖(views)和表單(forms),咱們以後會用到。

建立一個log-in視圖(view)

咱們將要開始使用Django認證(authentication)框架來容許用戶登陸咱們的網站。咱們的視圖(view)須要執行如下操做來登陸用戶:

  1. 經過提交的表單(form)獲取username和password
  2. 經過存儲在數據庫中的數據對用戶進行認證
  3. 檢查用戶是否可用
  4. 登陸用戶到網站中而且開始一個認證(authentication)會話(session)

首先,咱們要建立一個登陸表單(form)。在你的account應用目錄下建立一個新的forms.py文件,添加以下代碼:

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

這個表單(form)被用來經過數據庫認證用戶。請注意,咱們使用PasswordInput控件來渲染HTMLinput元素,包含type="password"屬性。編輯你的account應用中的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)中所做的基本登陸操做:當user_login被一個GET請求(request)調用,咱們實例化一個新的登陸表單(form)並經過form = LoginForm()在模板(template)中展現它。當用戶經過POST方法提交表單(form)時,咱們執行如下操做:

一、經過使用form = LoginForm(request.POST)使用提交的數據實例化表單(form)
二、檢查這個表單是否有效。若是無效,咱們在模板(template)中展現表單錯誤信息(舉個例子,好比用戶沒有填寫其中一個字段就進行提交)
三、若是提交的數據是有效的,咱們使用authenticate()方法經過數據庫對這個用戶進行認證(authentication)。這個方法帶入一個username和一個password,若是這個用戶成功的進行了認證則返回一個用戶對象,不然是None。若是用戶沒有被認證經過,咱們返回一個HttpResponse展現一條消息。
四、若是這個用戶認證(authentication)成功,咱們使用is_active屬性來檢查用戶是否可用。這是一個Django的User模型(model)屬性。若是這個用戶不可用,咱們返回一個HttpResponse展現信息。
五、若是用戶可用,咱們登陸這個用戶到網站中。咱們經過調用login()方法集合用戶到會話(session)中而後返回一條成功消息。

請注意authenticationlogin中的不一樣點:authenticate()檢查用戶認證信息,若是用戶是正確的則返回一個用戶對象;login()將用戶設置到當前的會話(session)中。

如今,你須要爲這個視圖(view)建立一個URL模式。在你的account應用目錄下建立一個新的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應用下的URL模式包含進去:

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)如今已經能夠經過URL進行訪問。如今是時候爲這個視圖(view)建立一個模板。由於以前你沒有這個項目的任何模板,你能夠開始建立一個主模板(template)可以被登陸模板(template)繼承使用。在account應用目錄中建立如下文件和結構:

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>

以上將是這個網站的基礎模板(template)。就像咱們在上一章項目中作過的同樣,咱們在這個主模板(template)中包含了CSS樣式。你能夠在本章的示例代碼中找到這些靜態文件。複製示例代碼中的account應用下的static/目錄到你的項目中的相同位置,這樣你就可使用這些靜態文件了。

基礎模板(template)定義了一個title和一個content區塊可讓被繼承的子模板(template)填充內容。

讓咱們爲咱們的登陸表單(form)建立模板(template)。打開account/login.html模板(template)添加以下代碼:

{% extends "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方式進行提交,因此咱們包含了{% csrf_token %}模板(template)標籤(tag)用來經過CSRF保護。你已經在第二章 使用高級特性擴展你的博客應用中學習過CSRF保護。

目前尚未用戶在你的數據庫中。你首先須要建立一個超級用戶用來登陸管理站點來管理其餘的用戶。打開命令行執行python manage.py createsuperuser。填寫username, e-mail以及password。以後經過命令python manage.py runserver運行開發環境,而後在你的瀏覽器中打開 http://127.0.0.1:8000/admin/ 。使用你剛纔建立的username和passowrd來進入管理站點。你會看到Django管理站點包含Django認證(authentication)框架中的UserGroup模型(models)。以下所示:

使用管理站點建立一個新的用戶而後打開 http://127.0.0.1:8000/account/login/ 。你會看到被渲染過的模板(template),包含一個登陸表單(form):

如今,只填寫一個字段保持另一個字段爲空進行表單(from)提交。在這例子中,你會看到這個表單(form)是無效的而且顯示了一個錯誤信息:

若是你輸入了一個不存在的用戶或者一個錯誤的密碼,你會獲得一個Invalid login信息。

若是你輸入了有效的認證信息,你會獲得一個Authenticated successfully消息:

使用Django認證(authentication)視圖(views)

Django在認證(authentication)框架中包含了一些開箱即用的表單(forms)和視圖(views)。你以前建立的登陸視圖(view)是一個很是好的練習用來理解Django中的用戶認證(authentication)過程。不管如何,你能夠在大部分的案例中使用默認的Django認證(authentication)視圖(views)。

Django提供如下視圖(views)來處理認證(authentication):

  • login:操做表單(form)中的登陸而後登陸一個用戶
  • logout:登出一個用戶
  • logout_then_login:登出一個用戶而後重定向這個用戶到登陸頁面

Django提供如下視圖(views)來操做密碼修改:

  • password_change:操做一個表單(form)來修改用戶密碼
  • password_change_done:當用戶成功修改他的密碼後提供一個成功提示頁面

Django還包含了如下視圖(views)容許用戶重置他們的密碼:

  • password_reset:容許用戶重置他的密碼。它會生成一條帶有一個token的一次性使用連接而後發送到用戶的郵箱中。
  • password_reset_done:告知用戶已經發送了一封能夠用來重置密碼的郵件到他的郵箱中。
  • password_reset_complete:當用戶重置完成他的密碼後提供一個成功提示頁面。

當你建立一個帶有用戶帳號的網站時,以上的視圖(views)能夠幫你節省不少時間。你能夠覆蓋這些視圖(views)使用的默認值,例如須要渲染的模板位置或者視圖(view)須要使用到的表單(form)。

你能夠經過訪問 https://docs.
djangoproject.com/en/1.8/topics/auth/default/#module-django.contrib.auth.views 獲取更多內置的認證(authentication)視圖(views)信息。

登陸和登出視圖(views)

編輯你的account應用下的urls.py文件,以下所示:

from django.conf.urls import url
from . import views
urlpatterns = [
    # previous login view
    # url(r'^login/$', views.user_login, name='login'),
    # login / logout urls
    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'),
]

咱們將以前建立的user_login視圖(view)URL模式進行註釋,而後使用Django認證(authentication)框架提供的login視圖(view)。

【譯者注】若是使用Django 1.10以上版本,urls.py 須要改寫爲如下方式(參見源書提供的源代碼):

from django.conf.urls import url
from django.contrib.auth.views import login
# With django 1.10 I need to pass the callable instead of 
# url(r'^login/$', 'django.contrib.auth.views.login', name='login')

from django.contrib.auth.views import logout
from django.contrib.auth.views import logout_then_login
from django.contrib.auth.views import password_change
from django.contrib.auth.views import password_change_done
from django.contrib.auth.views import password_reset
from django.contrib.auth.views import password_reset_done
from django.contrib.auth.views import password_reset_confirm
from django.contrib.auth.views import password_reset_complete
from . import views

urlpatterns = [
    # post views
    # url(r'^login/$', views.user_login, name='login'),
    
    # login logout
    url(r'^login/$', login, name='login'),
    url(r'^logout/$', logout, name='logout'),
    url(r'^logout-then-login/$', logout_then_login, name='logout_then_login'),
    # change password
    url(r'^password-change/$', password_change, name='password_change'),
    url(r'^password-change/done/$', password_change_done, name='password_change_done'),
    # reset password
    ## 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應用中的template目錄下建立一個新的目錄命名爲registration。這個路徑是Django認證(authentication)視圖(view)指望你的認證(authentication)模塊(template)默認的存放路徑。在這個新目錄中建立一個新的文件,命名爲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)和咱們以前建立的基本相似。Django默認使用位於django.contrib.auth.forms中的AuthenticationForm。這個表單(form)會嘗試對用戶進行認證,若是登陸不成功就會拋出一個驗證錯誤。在這個例子中,若是用戶提供了錯誤的認證信息,咱們能夠在模板(template)中使用{% if form.errors %}來找到錯誤。請注意,咱們添加了一個隱藏的HTML<input>元素來提交叫作next的變量值。當你在請求(request)中傳遞一個next參數(舉個例子:http://127.0.0.1:8000/account/login/?next=/account/),這個變量是登陸視圖(view)首個設置的參數。

next參數必須是一個URL。當這個參數被給予的時候,Django登陸視圖(view)將會在用戶登陸完成後重定向到給予的URL。

如今,在registrtion模板(template)目錄下建立一個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 %}

Django會在用戶登出的時候展現這個模板(template)。

在添加了URL模式以及登陸和登出視圖(view)的模板以後,你的網站已經準備好讓用戶使用Django認證(authentication)視圖進行登陸。

請注意,在咱們的地址配置中所包含的logtou_then_login視圖(view)不須要任何模板(template),由於它執行了一個重定向到登陸視圖(view)。

如今,咱們要建立一個新的視圖(view)給用戶,在他或她登陸他們的帳號後來顯示一個dashboard。打開你的account應用中的views.py文件,添加如下代碼:

from django.contrib.auth.decorators import login_required
@login_required
def dashboard(request):
    return render(request,
                 'account/dashboard.html',
                 {'section': 'dashboard'})

咱們使用認證(authentication)框架的login_required裝飾器(decorator)裝飾咱們的視圖(view)。login_required裝飾器(decorator)會檢查當前用戶是否經過認證,若是用戶經過認證,它會執行裝飾的視圖(view),若是用戶沒有經過認證,它會把用戶重定向到帶有一個名爲next的GET參數的登陸URL,該GET參數保存的變量爲用戶當前嘗試訪問的頁面URL。經過這些動做,登陸視圖(view)會將登陸成功的用戶重定向到用戶登陸以前嘗試訪問過的URL。請記住咱們在登陸模板(template)中的登陸表單(form)中添加的隱藏<input>就是爲了這個目的。

咱們還定義了一個section變量。咱們會使用該變量來跟蹤用戶在站點中正在查看的頁面。多個視圖(views)可能會對應相同的section。這是一個簡單的方法用來定義每一個視圖(view)對應的section。

如今,你須要建立一個給dashboard視圖(view)使用的模板(template)。在templates/account/目錄下建立一個新文件命名爲dashboard.html。添加以下代碼:

{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
  <h1>Dashboard</h1>
  <p>Welcome to your dashboard.</p>
{% endblock %}

以後,爲這個視圖(view)在account應用中的urls.py文件中添加以下URL模式:

urlpatterns = [
    # ...
    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')

這些設置的意義:

  • LOGIN_REDIRECT_URL:告訴Django用戶登陸成功後若是contrib.auth.views.login視圖(view)沒有獲取到next參數將會默認重定向到哪一個URL。
  • LOGIN_URL:重定向用戶登陸的URL(例如:使用login_required裝飾器(decorator))。
  • LOGOUT_URL:重定向用戶登出的URL。

咱們使用reverse_lazy()來經過它們的名字動態構建URL。reverse_lazy()方法就像reverse()所作的同樣reverses URLs,可是你能夠經過使用這種方式在你項目的URL配置被讀取以前進行reverse URLs。

讓咱們總結下目前爲止咱們都作了哪些工做:

  • 你在項目中添加了Django內置的認證(authentication)登陸和登出視圖(views)。
  • 你爲每個視圖(view)建立了定製的模板(templates),而且定義了一個簡單的視圖(view)讓用戶登陸後進行重定向。
  • 最後,你配置了你的Django設置使用默認的URLs。

如今,咱們要給咱們的主模板(template)添加登陸和登出連接將全部的一切都鏈接起來。

爲了作到這點,咱們必須肯定不管用戶是已登陸狀態仍是沒有登陸的時候,都會顯示適當的連接。經過認證(authentication)中間件當前的用戶被設置在HTTP請求(request)對象中。你能夠經過使用request.user訪問用戶信息。你會發現一個用戶對象在請求(request)中,即使這個用戶並無認證經過。一個未認證的用戶在請求(request)中被設置成一個AnonymousUser的實例。一個最好的方法來檢查當前的用戶是否經過認證是經過調用request.user.is_authenticated()

編輯你的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>

就像你所看到的,咱們只給經過認證(authentication)的用戶顯示站點菜單。咱們還檢查當前的section並經過使用CSS來給對應的<li>組件添加一個selected的class屬性來使當前section在菜單中進行高亮顯示。若是用戶已經經過認證(authentication),咱們還顯示用戶的名字(first_name)和一個登出的連接,不然,就是一個登出連接。

如今,在瀏覽器中打開 http://127.0.0.1:8000/account/login/ 。你會看到登陸頁面。輸入可用的用戶名和密碼而後點擊Log-in按鈕。你會看到以下圖所示:

你能看到經過CSS的做用 My Dashboard section 由於擁有一個 selected class 而高亮顯示。由於當前用戶已經經過了認證(authentication),因此用戶的名字在右上角進行了顯示。點擊Logout連接。你會看到以下圖所示:

在這個頁面中,你能看到用戶已經登出,而後,你沒法看到當前網站的任何菜單。在右上角如今顯示的是Log-in連接。

若是在你的登出頁面中看到了Django管理站點的登出頁面,檢查項目settings.py中的INSTALLED_APPS,確保django.contrib.adminaccount應用的後面。每一個模板(template)被定位在一樣的相對路徑時,Django模板(template)讀取器將會使用它找到的第一個應用中的模板(templates)。

修改密碼視圖(views)

咱們還須要咱們的用戶在登陸成功後能夠進行修改密碼。咱們要集成Django認證(authentication)視圖(views)來修改密碼。打開account應用中的urls.py文件,添加以下URL模式:

# change password urls
url(r'^password-change/$',
   'django.contrib.auth.views.password_change',
   name='password_change'),
url(r'^password-change/done/$',
   'django.contrib.auth.views.password_change_done',
   name='password_change_done'),

password_change 視圖(view)將會操做表單(form)進行修改密碼,當用戶成功的修改他的密碼後 password_change_done 將會顯示一條成功信息。讓咱們爲每一個視圖(view)建立一個模板(template)。

在你的account應用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)。如今,在相同的目錄下建立另外一個文件,命名爲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)只包含顯示一條成功的信息 當用戶成功的修改他們的密碼。

在瀏覽器中打開 http://127.0.0.1:8000/account/password-change/ 。若是你的用戶沒有登陸,瀏覽器會重定向你到登陸頁面。在你成功認證(authentication)登陸後,你會看到以下圖所示的修改密碼頁面:

在表單(form)中填寫你的舊密碼和新密碼,而後點擊Change按鈕。你會看到以下所示的成功頁面:

登出再使用新的密碼進行登陸來驗證每件事是否如預期同樣工做。

重置密碼視圖(views)

account應用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應用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 %}

如今,在相同的目錄下添加另外一個文件命名爲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)會被用來渲染髮送給用戶的重置密碼郵件。

在相同目錄下添加另外一個文件命名爲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 %}

再建立另外一個模板(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 %}

在以上模板中,咱們將會檢查重置連接是否有效。Django重置密碼視圖(view)會設置這個變量而後將它帶入這個模板(template)的上下文環境中。若是重置連接有效,咱們展現用戶密碼重置表單(form)。

建立另外一個模板(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應用中的/registration/login.html模板(template),添加以下代碼在<form>元素以後:

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

如今,在瀏覽器中打開 http://127.0.0.1:8000/account/login/ 而後點擊Forgotten your password?連接。你會看到以下圖所示頁面:

在這部分,你須要在你項目中的settings.py中添加一個SMTP配置,這樣Django才能發送e-mails。咱們已經在第二章 使用高級特性來優化你的blog學習過如何添加e-mail配置。固然,在開發期間,咱們能夠配置Django在標準輸出中輸出e-mail內容來代替經過SMTP服務發送郵件。Django提供一個e-mail後端來輸出e-mail內容到控制器中。編輯項目中settings.py文件,添加以下代碼:

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

EMAIL_BACKEND設置這個類用來發送e-mails。

回到你的瀏覽器中,填寫一個存在用戶的e-mail地址,而後點擊Send e-mail按鈕。你會看到以下圖所示頁面:

當你運行開發服務的時候看眼控制檯輸出。你會看到以下所示生成的e-mail:

IME-Version: 1.0
 Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
Subject: Password reset on 127.0.0.1:8000
From: webmaster@localhost
To: user@domain.com
Date: Thu, 24 Sep 2015 14:35:08 -0000
Message-ID: <20150924143508.62996.55653@zenx.local>
Someone asked for password reset for email user@domain.com. Follow the link below:
http://127.0.0.1:8000/account/password-reset/confirm/MQ/45f-9c3f30caafd523055fcc/
Your username, in case you've forgotten: zenx

這封e-mail被咱們以前建立的password_reset_email.html模板給渲染。這個給你重置密碼的URL帶有一個Django動態生成的token。在瀏覽器中打開這個連接,你會看到以下所示頁面:

這個頁面對應password_reset_confirm.html模板(template)用來設置新密碼。填寫新的密碼而後點擊Change my password button。Django會建立一個新的加密後密碼保存進數據庫,你會看到以下圖所示頁面:

如今你可使用你的新密碼登陸你的帳號。每一個用來設置新密碼的token只能使用一次。若是你再次打開你以前獲取的連接,你會獲得一條信息告訴你這個token已經無效了。

你在項目中集成了Django認證(authentication)框架的視圖(views)。這些視圖(views)對大部分的狀況都適合。固然,若是你須要一種不一樣的行爲你能建立你本身的視圖。

用戶註冊和用戶profiles

現有的用戶已經能夠登陸,登出,修改他們的密碼,以及當他們忘記密碼的時候重置他們的密碼。如今,咱們須要構建一個視圖(view)容許訪問者建立他們的帳號。

用戶註冊

讓咱們建立一個簡單的視圖(view)容許用戶在咱們的網站中進行註冊。首先,咱們須要建立一個表單(form)讓用戶填寫用戶名,他們的真實姓名以及密碼。編輯account應用新目錄下的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']

咱們爲User模型(model)建立了一個model表單(form)。在咱們的表單(form)中咱們只包含了模型(model)中的username,first_name,email字段。這些字段會在它們對應的模型(model)字段上進行驗證。例如:若是用戶選擇了一個已經存在的用戶名,將會獲得一個驗證錯誤。咱們還添加了兩個額外的字段passwordpassword2給用戶用來填寫他們的新密碼和肯定密碼。咱們定義了一個clean_password2()方法去檢查第二次輸入的密碼是否和第一次輸入的保持一致,若是不一致這個表單將會是無效的。當咱們經過調用is_valid()方法驗證這個表單(form)時這個檢查會被執行。你能夠提供一個clean_<fieldname>()方法給任何一個你的表單(form)字段用來清理值或者拋出表單(from)指定的字段的驗證錯誤。表單(forms)還包含了一個clean()方法用來驗證表單(form)的全部內容,這對驗證須要依賴其餘字段的字段是很是有用的。

Django還提供一個UserCreationForm表單(form)給你使用,它位於django.contrib.auth.forms很是相似與咱們剛纔建立的表單(form)。

編輯account應用中的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})

這個建立用戶帳號的視圖(view)很是簡單。爲了保護用戶的隱私,咱們使用User模型(model)的set_password()方法將用戶的原密碼進行加密後再進行保存操做。

如今,編輯account應用中的urls.py文件,添加以下URL模式:

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

最後,建立一個新的模板(template)在account/模板(template)目錄下,命名爲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 %}

在相同的目錄中添加一個模板(template)文件命名爲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 %}

如今,在瀏覽器中打開 http://127.0.0.1:8000/account/register/ 。你會看到你建立的註冊頁面:

填寫用戶信息而後點擊Create my account按鈕。若是全部的字段都驗證都過,這個用戶將會被建立而後會獲得一條成功信息,以下所示:

點擊log-in連接輸入你的用戶名和密碼來驗證帳號是否成功建立。

如今,你還能夠添加一個註冊連接在你的登陸模板(template)中。編輯registration/login.html模板(template)而後替換如下內容:

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

爲:

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

如此,咱們就能夠從登陸頁面進入註冊頁面。

擴展User模型(model)

當你須要處理用戶帳號,你會發現Django認證(authentication)框架的User模型(model)只適應通常的案例。不管如何,User模型(model)只有一些最基本的字段。你可能但願擴展User模型包含額外的數據。最好的辦法就是建立一個profile模型(model)包含全部額外的字段而且和Django的User模型(model)作一對一的關聯。

編輯account應用中的model.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 'Profile for user {}'.format(self.user.username)

爲了保持你的代碼通用化,當須要定義模型(model)和用戶模型的關係時,使用get_user_model()方法來取回用戶模型(model)並使用AUTH_USER_MODEL設置來引用這個用戶模型,替代直接引用auth的User模型(model)。

user一對一字段容許咱們關聯用戶和profiles。photo字段是一個ImageField字段。你須要安裝一個Python包來管理圖片,使用PIL(Python Imaging Library)或者Pillow(PIL的分叉),在shell中運行一下命令來安裝Pillow

pip install Pillow==2.9.0

爲了Django能在開發服務中管理用戶上傳的多媒體文件,在項目setting.py文件中添加以下設置:

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

MEDIA_URL 是管理用戶上傳的多媒體文件的主URL,MEDIA_ROOT是這些文件在本地保存的路徑。咱們動態的構建這些路徑相對咱們的項目路徑來確保咱們的代碼更通用化。

如今,編輯bookmarks項目中的主urls.py文件,修改代碼以下所示:

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


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

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

在這種方法中,Django開發服務器將會在開發時改變對多媒體文件的服務。

static()幫助函數最適合在開發環境中使用而不是在生產環境使用。絕對不要在生產環境中使用Django來服務你的靜態文件。

打開終端運行如下命令來爲新的模型(model)建立數據庫遷移:

python manage.py makemigrations

你會得到如下輸出:

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

接着,同步數據庫經過如下命令:

python manage.py migrate

你會看到包含如下內容的輸出:

Applying account.0001_initial... OK

編輯account應用中的admin.py文件,在管理站點註冊Profiel模型(model),以下所示:

from django.contrib import admin
from .models import Profile
class ProfileAdmin(admin.ModelAdmin):
    list_display = ['user', 'date_of_birth', 'photo']
admin.site.register(Profile, ProfileAdmin)

使用python manage.py runnserver命令從新運行開發服務。如今,你能夠看到Profile模型已經存在你項目中的管理站點中,以下所示:

如今,咱們要讓用戶能夠在網站編輯它們的profile。添加以下的模型(model)表單(forms)到account應用中的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')

這兩個表單(forms)的功能:

  • UserEditForm:容許用戶編輯它們的first name,last name, e-mail 這些儲存在User模型(model)中的內置字段。
  • ProfileEditForm:容許用戶編輯咱們存儲在定製的Profile模型(model)中的額外數據。用戶能夠編輯他們的生日數據以及爲他們的profile上傳一張照片。

編輯account應用中的view.py文件,導入Profile模型(model),以下所示:

from .models import Profile

而後添加以下內容到register視圖(view)中的new_user.save()下方:

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

當用戶在咱們的站點中註冊,咱們會建立一個對應的空的profile給他們。你須要在管理站點中爲以前建立的用戶們一個個手動建立對應的Profile對象。

如今,咱們要讓用戶可以編輯他們的pfofile。添加以下代碼到相同文件中:

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裝飾器decorator是由於用戶編輯他們的profile必須是認證經過的狀態。在這個例子中,咱們使用兩個模型(model)表單(forms):UserEditForm用來存儲數據到內置的User模型(model)中,ProfileEditForm用來存儲額外的profile數據。爲了驗證提交的數據,經過is_valid()方法是否都返回True咱們來檢查每一個表單(forms)。在這個例子中,咱們保存兩個表單(form)來更新數據庫中對應的對象。

account應用中的urls.py文件中添加以下URL模式:

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

最後,在templates/account/中建立一個新的模板(template)命名爲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 %}

咱們在表單(form)中包含enctype="multipart/form-data"用來支持文件上傳。咱們使用一個HTML表單來提交兩個表單(forms): user_formprofile_form

註冊一個新用戶而後打開 http://127.0.0.1:8000/account/edit/。你會看到以下所示頁面:

如今,你能夠編輯dashboard頁面包含編輯profile的頁面連接和修改密碼的頁面連接。打開account/dashboard.html模板(model)替換以下代碼:

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

爲:

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

用戶如今能夠從他們的dashboard訪問編輯他們的profile的表單。

使用一個定製User模型(model)

Django還提供一個方法可使用你本身定製的模型(model)來替代整個User模型(model)。你本身的用戶類須要繼承Django的AbstractUser類,這個類提供了一個抽象的模型(model)用來完整執行默認用戶。你可訪問 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#substituting-a-custom-user-model來得到這個方法的更多信息。

使用一個定製的用戶模型(model)將會帶給你不少的靈活性,可是它也可能給一些須要與User模型(model)交互的即插即用的應用集成帶來必定的困難。

使用messages框架

當處理用戶的操做時,你可能想要通知你的用戶關於他們操做的結果。Django有一個內置的messages框架容許你給你的用戶顯示一次性的提示。messages框架位於django.contrib.messages,當你使用python manage.py startproject命令建立一個新項目的時候,messages框架就被默認包含在settings.py文件中的INSTALLED_APPS中。你會注意到你的設置文件中在MIDDLEWARE_CLASSES設置裏包含了一個名爲django.contrib.messages.middleware.MessageMiddleware的中間件。messages框架提供了一個簡單的方法添加消息給用戶。消息被存儲在數據庫中而且會在用戶的下一次請求中展現。你能夠在你的視圖(views)中導入messages模塊來使用消息messages框架,用簡單的快捷方式添加新的messages,以下所示:

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

你可使用add_message()方法建立新的messages或用如下任意一個快捷方法:

  • success():當操做成功後顯示成功的messages
  • info():展現messages
  • warning():某些尚未達到失敗的程度但已經包含有失敗的風險,警報用
  • error():操做沒有成功或者某些事情失敗
  • debug():在生產環境中這種messages會移除或者忽略

讓咱們顯示messages給用戶。由於messages框架是被項目全局應用,咱們能夠在主模板(template)給用戶展現messages。打開base.html模板(template)在id爲header<div>和id爲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 %}

messages框架帶有一個上下文環境(context)處理器用來添加一個messages變量給請求的上下文環境(context)。因此你能夠在模板(template)中使用這個變量用來給用戶顯示當前的messages。

如今,讓咱們修改edit視圖(view)來使用messages框架。編輯應用中的views.py文件,使edit視圖(view)以下所示:

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)
        # ...

當用戶成功的更新他們的profile時咱們就添加了一條成功的message,但若是某個表單(form)無效,咱們就添加一個錯誤message。

在瀏覽器中打開 http://127.0.0.1:8000/account/edit/ 編輯你的profile。當profile更新成功,你會看到以下message:

當表單(form)是無效的,你會看到以下message:

建立一個定製的認證(authentication)後臺

Django容許你經過不一樣的來源進行認證(authentication)。AUTHENTICATION_BACKENDS設置包含了全部的給你的項目的認證(authentication)後臺。默認的,這個設置以下所示:

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

默認的ModelBackend經過數據庫使用django.contrib.auth中的User模型(model)來認證(authentication)用戶。這適用於你的大部分項目。固然,你還能夠建立定製的後臺經過其餘的來源例如一個LDAP目錄或者其餘任何系統來認證你的用戶。

你能夠經過訪問 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#other-authentication-sources 得到更多的信息關於自定義的認證(authentication)。

當你使用django.contrib.authauthenticate()函數,Django會經過每個定義在AUTHENTICATION_BACKENDS中的後臺一個接一個地嘗試認證(authentication)用戶,直到其中有一個後臺成功的認證該用戶纔會中止進行認證。只有全部的後臺都沒法進行用戶認證(authentication),他或她纔不會在你的站點中經過認證(authentication)。

Django提供了一個簡單的方法來定義你本身的認證(authentication)後臺。一個認證(authentication)後臺就是提供了以下兩種方法的一個類:

  • authenticate():將用戶信息當成參數,若是用戶成功的認證(authentication)就須要返回True,反之,須要返回False
  • get_user():將用戶的ID當成參數而後須要返回一個用戶對象。

建立一個定製認證(authentication)後臺很是容易,就是編寫一個Python類實現上面兩個方法。咱們要建立一個認證(authentication)後臺讓用戶在咱們的站點中使用他們e-mail替代他們的用戶名來進行認證(authentication)。

在你的account應用中建立一個新的文件命名爲authentication.py,爲它添加以下代碼:

from django.contrib.auth.models import User

class EmailAuthBackend(object):
    """
    Authenticate 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:
            return None
    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
return None

這是一個簡單的認證(authentication)後臺。authenticate()方法接收了usernamepassword兩個可選參數。咱們可使用不一樣的參數,可是咱們須要使用usernamepassword來確保咱們的後臺能夠立馬在認證(authentication)框架視圖(views)中工做。以上代碼完成了如下工做內容:

  • authenticate():咱們嘗試經過給予的e-mail地址獲取一個用戶和使用User模型(model)中內置的check_password()方法來檢查密碼。這個方法會對給予密碼進行哈希化來和數據庫中存儲的加密密碼進行匹配。
  • get_user():咱們經過user_id參數獲取一個用戶。Django使用這個後臺來認證用戶以後取回User對象放置到持續的用戶會話中。

編輯項目中的settings.py文件添加以下設置:

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

咱們保留默認的ModelBacked用來保證用戶仍然能夠經過用戶名和密碼進行認證,接着咱們包含進了咱們本身的email-based認證(authentication)後臺。如今,在瀏覽器中打開 http://127.0.0.1:8000/account/login/ 。請記住,Django會對每一個後臺都嘗試進行用戶認證(authentication),因此你可使用用戶名或者使用email來進行無縫登陸。

AUTHENTICATION_BACKENDS設置中的後臺排列順序。若是相同的認證信息在多個後臺都是有效的,Django會中止在第一個成功認證(authentication)經過的後臺,再也不繼續進行認證(authentication)。

爲你的站點添加社交認證(authentication)

你能夠但願給你的站點添加一些社交認證(authentication)服務,例如 FacebookTwitter或者Google(國內就算了- -|||)。Python-social-auth是一個Python模塊提供了簡化的處理爲你的網站添加社交認證(authentication)。經過使用這個模塊,你可讓你的用戶使用他們的其餘服務的帳號來登陸你的網站。你能夠訪問 https://github.com/omab/python-social-auth 獲得這個模塊的代碼。

這個模塊自帶不少認證(authentication)後臺給不一樣的Python框架,其中就包含Django。

使用pip來安裝這個包,打開終端運行以下命令:

pip install python-social-auth==0.2.12

安裝成功後,咱們須要在項目settings.py文件中的INSTALLED_APPS設置中添加social.apps.django_app.default

INSTALLED_APPS = (
    #...
    'social.apps.django_app.default',
)

這個default應用會在Django項目中添加python-social-auth。如今,運行如下命令來同步python-social-auth模型(model)到你的數據庫中:

python manage.py migrate

你會看到以下default應用的數據遷移輸出:

Applying default.0001_initial... OK
Applying default.0002_add_related_name... OK
Applying default.0003_alter_email_max_length... OK

python-social-auth包含了不少服務的後臺。你能夠訪問 https://python-social-auth.readthedocs.org/en/latest/backends/index.html#supported-backends 看到全部的後臺支持。

咱們要包含的認證(authentication)後臺包括FacebookTwitterGoogle

你須要在你的項目中添加社交登陸URL模型。打開bookmarks項目中的主urls.py文件,添加以下URL模型:

url('social-auth/',
    include('social.apps.django_app.urls', namespace='social')),

爲了確保社交認證(authentication)能夠工做,你還須要配置一個hostname,由於有些服務不容許重定向到127.0.0.1localhost。爲了解決這個問題,在Linux或者Mac OSX下,編輯你的/etc/hosts文件添加以下內容:

127.0.0.1 mysite.com

這是用來告訴你的計算機指定mysite.com hostname指向你的本地機器。若是你使用Windows,你的hosts文件在 C:\Winwows System32\Drivers\etc\hosts

爲了驗證你的host重定向是否可用,在瀏覽器中打開 http://mysite.com:8000/account/login/ 。若是你看到你的應用的登陸頁面,host重定向已經可用。

使用Facebook認證(authentication)

(譯者注:如下的幾種社交認證操做步驟可能已通過時,請根據實際狀況操做)
爲了讓你的用戶可以使用他們的Facebook帳號來登陸你的網站,在項目settings.py文件中的AUTHENTICATION_BACKENDS設置中添加以下內容:

'social.backends.facebook.Facebook2OAuth2',

爲了添加Facebook的社交認證(authentication),你須要一個Facebook開發者帳號,而後你必須建立一個新的Facebook應用。在瀏覽器中打開 https://developers.facebook.com/apps/?action=create 點擊Add new app按鈕。點擊Website平臺而後爲你的應用取名爲Bookmarks,輸入 http://mysite.com:8000/ 做爲你的網站URL。跟隨快速開始步驟而後點擊Create App ID

回到網站的Dashboard。你會看到相似下圖所示的:

拷貝App IDApp Secret關鍵值,將它們添加在項目中的*settings.py**文件中,以下所示:

SOCIAL_AUTH_FACEBOOK_KEY = 'XXX' # Facebook App ID
SOCIAL_AUTH_FACEBOOK_SECRET = 'XXX' # Facebook App Secret

此外,你還能夠定義一個SOCIAL_AUTH_FACEBOOK_SCOPE設置若是你想要訪問Facebook用戶的額外權限,例如:

SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']

最後,打開registration/login.html模板(template)而後添加以下代碼到content block中:

<div class="social">
  <ul>
    <li class="facebook"><a href="{% url "social:begin" "facebook" %}">Sign in with Facebook</a></li>
  </ul> 
</div>

在瀏覽器中打開 http://mysite.com:8000/account/login/ 。如今你的登陸頁面會以下圖所示:

點擊**Login with Facebook按鈕。你會被重定向到Facebook,而後你會看到一個對話詢問你的權限是否讓Bookmarks*應用訪問你的公共Facebook profile:

點擊Okay按鈕。Python-social-auth會對認證(authentication)進行操做。若是每一步都沒有出錯,你會登陸成功而後被重定向到你的網站的dashboard頁面。請記住,咱們已經使用過這個URL在LOGIN_REDIRECT_URL設置中。就像你所看到的,在你的網站中添加社交認證(authentication)是很是簡單的。

使用Twitter認證(authentication)

爲了使用Twitter進行認證(authentication),在項目settings.py中的AUTHENTICATION_BACKENDS設置中添加以下內容:

'social.backends.twitter.TwitterOAuth',

你須要在你的Twitter帳戶中建立一個新的應用。在瀏覽器中打開 https://apps.twitter.com/app/new 而後輸入你應用信息,包含如下設置:

  • Website:http://mysite.com:8000/
  • Callback URL:http://mysite.com:8000/social-auth/complete/twitter/

確保你勾選了複選款Allow this application to be used to Sign in with Twitter。以後點擊Keys and Access Tokens。你會看到以下所示信息:

拷貝Consumer KeyConsumer Secret關鍵值,將它們添加到項目settings.py的設置中,以下所示:

SOCIAL_AUTH_TWITTER_KEY = 'XXX' # Twitter Consumer Key
SOCIAL_AUTH_TWITTER_SECRET = 'XXX' # Twitter Consumer Secret

如今,編輯login.html模板(template),在<ul>元素中添加以下代碼:

<li class="twitter"><a href="{% url "social:begin" "twitter" %}">Login with Twitter</a></li>

在瀏覽器中打開 http://mysite.com:8000/account/login/ 而後點擊Login with Twitter連接。你會被重定向到Twitter而後它會詢問你受權給應用,以下所示:

點擊Authorize app按鈕。你會登陸成功而且重定向到你的網站dashboard頁面。

使用Google認證(authentication)

Google提供OAuth2認證(authentication)。你能夠訪問 https://developers.google.com/accounts/docs/OAuth2 得到關於Google OAuth2的信息。

首先,你徐闖建立一個API key在你的Google開發者控制檯。在瀏覽器中打開 https://console.developers.google.com/project 而後點擊Create project按鈕。輸入一個名字而後點擊Create按鈕,以下所示:

在項目建立以後,點擊在左側菜單的APIs & auth連接,而後點擊Credentials部分。點擊Add credentials按鈕,而後選擇OAuth2.0 client ID,以下所示:

Google首先會詢問你配置贊成信息頁面。這個頁面將會展現給用戶告知他們是否贊成使用他們的Google帳號來登陸訪問你的網站。點擊Configure consent screen按鈕。選擇你的e-mail地址,填寫BookmarksProduct name,而後點擊Save按鈕。這個給你的項目使用的贊成信息頁面將會配置完成而後你會被重定向去完成建立你的Client ID。

在表單(form)中填寫如下內容:

  • Application type: 選擇Web application
  • Name: 輸入Bookmarks
  • Authorized redirect URLs:輸入 http://mysite.com:8000/social-auth/complete/google-oauth2/

這表單(form)將會以下所示:

點擊Create按鈕。你將會得到Client IDClient Secret關鍵值。在你的settings.py中添加它們,以下所示:

SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' # Google Consumer Key
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' # Google Consumer Secret

在Google開發者控制檯的左方菜單,APIs & auth部分的下方,點擊APIs連接。你會看到包含全部Google Apis的列表。點擊 Google+ API而後點擊Enable API按鈕在如下頁面中:

編輯login.html模板(template)在<ul>元素中添加以下代碼:

<li class="google"><a href="{% url "social:begin" "google" %}">Login with Google</a></li>

在瀏覽器中打開 http://mysite.com:8000/account/login/ 。登陸頁面將會看上去以下圖所示:

點擊Login with Google按鈕。你將會被重定向到Google而且被詢問權限經過咱們以前配置的贊成信息頁面:

點擊Accept按鈕。你會登陸成功並重定向到你的網站的dashboard頁面。

咱們已經添加了社交認證(authentication)到咱們的項目中。python-social-auth模塊還包含更多其餘很是熱門的在線服務。

總結

在本章中,你學習瞭如何建立一個認證(authentication)系統到你的網站而且建立了定製的用戶profile。你還爲你的網站添加了社交認證(authentication)。

在下一章中,你會學習如何建立一個圖片收藏系統(image bookmarking system),生成圖片縮微圖,建立AJAX視圖(views)。

譯者總結

終於寫到了這裏,呼出一口氣,第四章的頁數是前幾章的兩倍,在翻譯以前還有點擔憂會不會堅持不下去,不過看樣子我仍是堅持了下來,並且發現一旦翻譯起來就不想中止(- -|||莫非心中真的有翻譯之魂!?)。這一章仍是比較基礎,主要介紹了集成用戶的認證系統到網站中,比較有用的是經過第三方的平臺帳戶登陸,惋惜3個平臺Facbook,Twitter,Google國內都很差訪問,你們練習的時候仍是用國內的QQ,微信,新浪等平臺來練習吧。第五章的翻譯不清楚何時能完成,也許過年前也可能過年後,反正無論如何,這本書我必定要翻譯到最後!

最後,請保佑我公司年會讓我抽到特大獎,集各位祈禱之力,哈哈哈哈!

相關文章
相關標籤/搜索