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


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

2017年1月4日初稿發布

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

(譯者注:祝大家新年快樂,這次帶來《Django By Example》第四章的翻譯,這章非常的實用,就這樣)

第四章

創建一個社交網站

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

本章將會覆蓋一下幾點:

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

讓我們開始創建我們的新項目吧。

創建一個社交網站項目

我們要創建一個社交應用允許用戶分享他們在網上找到的圖片。我們需要為這個項目構建以下元素:

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

本章主要講述第一點。

開始你的社交網站項目

打開終端使用如下命令行為你的項目創建一個虛擬環境並且激活它:

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)時,我們執行以下操作:

1、通過使用form = LoginForm(request.POST)使用提交的數據實例化表單(form)
2、檢查這個表單是否有效。如果無效,我們在模板(template)中展示表單錯誤信息(舉個例子,比如用戶沒有填寫其中一個字段就進行提交)
3、如果提交的數據是有效的,我們使用authenticate()方法通過數據庫對這個用戶進行認證(authentication)。這個方法帶入一個username和一個password,如果這個用戶成功的進行了認證則返回一個用戶對象,否則是None。如果用戶沒有被認證通過,我們返回一個HttpResponse展示一條消息。
4、如果這個用戶認證(authentication)成功,我們使用is_active屬性來檢查用戶是否可用。這是一個Django的User模型(model)屬性。如果這個用戶不可用,我們返回一個HttpResponse展示信息。
5、如果用戶可用,我們登錄這個用戶到網站中。我們通過調用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 然后輸入你應用信息,包含以下設置:

確保你勾選了復選款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)中填寫以下內容:

這表單(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,微信,新浪等平台來練習吧。第五章的翻譯不清楚什么時候能完成,也許過年前也可能過年后,反正不管如何,這本書我一定要翻譯到最后!

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM