第四章Django by example

創(chuàng)建一個社交網站

重點:

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

開始社交網站項目

django-admin startproject bookmarks#創(chuàng)建項目文件夾
cd bookmarks
django-admin startapp account
#settings文件installed_apps中添加account應用

注意]罕肌R谌椤! 要把INSTALLED_APPS 的‘account’,放在'django.contrib.admin'前面但金,否則會優(yōu)先尋找內置admin應用的account果善。

使用認證框架

Django擁有一個內置的認證(authentication)框架用來操作用戶認證(authentication)都办,會話(sessions),權限(permissions)以及用戶組镜会。這個認證(authentication)系統(tǒng)包含了一些普通用戶的操作視圖(views)檬寂,例如:登錄,登出戳表,修改密碼以及重置密碼桶至。

這個認證(authentication)框架位于django.contrib.auth昼伴,被其他Django的contrib包調用。
當你使用startproject命令創(chuàng)建一個新的Django項目镣屹,認證(authentication)框架已經在你的項目設置中默認包含圃郊。它是由django.contrib.auth應用和你的項目設置中的MIDDLEWARE_CLASSES中的兩個中間件類組成,如下:

AuthenticationMiddleware:使用會話(sessions)將用戶和請求(requests)進行關聯(lián)
SessionMiddleware:通過請求(requests)操作當前會話(sessions)
中間件就是一個在請求和響應階段帶有全局執(zhí)行方法的類女蜈。

這個認證(authentication)系統(tǒng)還包含了以下模型(models):

  • User:一個包含了基礎字段的用戶模型(model)持舆;這個模型(model)的主要字段有:username, password, email, first_name, last_name, is_active伪窖。
  • Group:一個組模型(model)用來分類用戶
  • Permission:執(zhí)行特定操作的標識
    這個框架還包含默認的認證(authentication)視圖(views)和表單(forms)

創(chuàng)建一個log-in視圖(view)

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

from django import forms #導入表單文件夾
class LoginForm(forms.Form):#繼承表單類
    username = forms.CharField(max_length=200)#username為字符串字段
    password = forms.CharField(widget=forms.PasswordInput)# password為字符串字段逸寓,控件為PasswordInput
#這個表單(form)被用來通過數據庫認證用戶。請注意覆山,我們使用PasswordInput控件來渲染HTMLinput元素竹伸,包含type="password"屬性

創(chuàng)建視圖

from django.contrib.auth import authenticate, login
from django.http import HttpResponse
from django.shortcuts import render

from .forms import LoginForm


def user_login(request):
    if request.method == "POST":
        form = LoginForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            username = cd['username']
            password = cd['password']
            user = authenticate(username=username, password=password)  # 對過數據庫對這個用戶進行認證,成功返回user對象簇宽,失敗返回None
            if user is not None:
                if user.is_active:  # 用is_active屬性來檢查用戶是否可用
                    login(request, user)  # login()將用戶設置到當前的會話(session)中佩伤。
                    return HttpResponse("登陸成功")
                else:
                    return HttpResponse("用戶被禁止登陸")
            else:
                return HttpResponse("用戶不存在")
    else:
        form = LoginForm()
    return render(request, 'account/login.html', {'form': form})

創(chuàng)建url模式

from django.conf.urls import url

from . import views

urlpatterns = [
    url('^login$', views.user_login, name="login"),
]
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')),
]

創(chuàng)建html文件
結構

    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>

login.html文件

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


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

Django在認證(authentication)框架中包含了一些開箱即用的表單(forms)和視圖(views)。你之前創(chuàng)建的登錄視圖(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的一次性使用鏈接然后發(fā)送到用戶的郵箱中孤荣。

  • password_reset_done:告知用戶已經發(fā)送了一封可以用來重置密碼的郵件到他的郵箱中。

  • password_reset_complete:當用戶重置完成他的密碼后提供一個成功提示頁面须揣。
    當你創(chuàng)建一個帶有用戶賬號的網站時盐股,以上的視圖(views)可以幫你節(jié)省很多時間。你可以覆蓋這些視圖(views)使用的默認值耻卡,例如需要渲染的模板位置或者視圖(view)需要使用到的表單(form)疯汁。
    更多信息
    (https://docs.djangoproject.com/en/1.8/topics/auth/default/#module-django.contrib.auth.views)

登錄和登出視圖(views)

from django.conf.urls import url
from . import views
from django.contrib.auth.views import login,logout,logout_then_login  # 導入django自帶的視圖函數

urlpatterns = [
    # url('^login/$', views.user_login, name="login"),
    url('^login/$',login,name='login'),
    url('^logout/$', logout, name='logout'),
    url('^logout_then_login/$', logout_then_login, name='logout_then_login'),
]

在account應用中的template目錄下創(chuàng)建一個新的目錄命名為registration。這個路徑是Django認證(authentication)視圖(view)期望你的認證(authentication)模塊(template)默認的存放路徑卵酪。在這個新目錄中創(chuàng)建一個新的文件幌蚊,命名為login.htm

{% 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 }}" />#隱藏標簽,參數next
      <p><input type="submit" value="Log-in"></p>
    </form>
  </div>
 {% endblock %}

備注:在任何頁面中溃卡,只要有登陸的<a>標簽溢豆,比如<a href="{% url 'login' %}?next={{request.path}}",此時,url符合login urls匹配瘸羡,交由login視圖函數處理漩仙,同時傳給視圖函數next參數,login視圖函數中,通過 redirect_to = request.POST.get('next', request.GET.get('next', ''))從get中或者post中獲得next參數值队他。
一開始是GET方式卷仑,渲染表單,同時在form中添加了一個隱藏的input標簽提供next參數麸折,之后提供POST方式锡凝,同樣交由login視圖函數來處理,此時磕谅,從post中獲得next參數私爷,然后redirect(redirect_to)重定向到next這個頁面N砉住2布小!

我們添加了一個隱藏的HTML<input>元素來提交叫做next的變量值捌浩。當你在請求(request)中傳遞一個next參數(舉個例子:http://127.0.0.1:8000/account/login/?next=/account/)放刨,這個變量是登錄視圖(view)首個設置的參數。
next參數必須是一個URL尸饺。當這個參數被給予的時候进统,Django登錄視圖(view)將會在用戶登錄完成后重定向到給予的URL。

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

設置主頁dashboard.html及base.html

<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>
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
  <h1>Dashboard</h1>
  <p>Welcome to your dashboard.</p>
{% endblock %}
urlpatterns = [
    # ...
    url(r'^$', views.dashboard, name='dashboard'),
]

settings中設置

from django.core.urlresolvers import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('dashboard')#告訴Django用戶登錄成功后如果contrib.auth.views.login視圖(view)沒有獲取到next參數將會默認重定向到哪個UR
LOGIN_URL = reverse_lazy('login')#重定向用戶登錄的URL(例如:使用login_required裝飾器(decorator))
LOGOUT_URL = reverse_lazy('logout')#重定向用戶登出的URL浪听。

我們使用reverse_lazy()來通過它們的名字動態(tài)構建URL螟碎。reverse_lazy()方法就像reverse()所做的一樣reverses URLs,但是你可以通過使用這種方式在你項目的URL配置被讀取之前進行reverse URLs迹栓。


修改密碼視圖(views)

urlpatterns設置

# 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_form.html是django自帶的視圖使用的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 %}

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

重置密碼視圖(views)

使用django.contrib.auth.views中的
password_reset,
password_reset_done,
password_reset_confirm,
password_reset_complete

# 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'),

先編輯password_reset默認的2個html文件掉分,template_name='registration/password_reset_form.html', email_template_name='registration/password_reset_email.html'

password_reset_form.html(視圖函數會處理此html,同時克伊,發(fā)送郵件以及reverse生成password_reset_done的url,生成url后由password_reset_done函數來處理)

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

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

從收到郵件的連接url進入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">
      {{ 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 %}

修改完密碼后的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 %}

以上完成了重置密碼的過程酥郭,別忘了在login中添加連接以及settings中設置發(fā)送郵件相關配置(第二章中記錄)

學習源于夜夜月翻譯的django by example

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市愿吹,隨后出現(xiàn)的幾起案子不从,更是在濱河造成了極大的恐慌,老刑警劉巖犁跪,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椿息,死亡現(xiàn)場離奇詭異,居然都是意外死亡坷衍,警方通過查閱死者的電腦和手機撵颊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惫叛,“玉大人倡勇,你說我怎么就攤上這事。” “怎么了妻熊?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵夸浅,是天一觀的道長。 經常有香客問我扔役,道長帆喇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任亿胸,我火速辦了婚禮坯钦,結果婚禮上,老公的妹妹穿的比我還像新娘侈玄。我一直安慰自己婉刀,他們只是感情好,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布序仙。 她就那樣靜靜地躺著突颊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪潘悼。 梳的紋絲不亂的頭發(fā)上律秃,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機與錄音治唤,去河邊找鬼棒动。 笑死,一個胖子當著我的面吹牛宾添,可吹牛的內容都是我干的船惨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辞槐,長吁一口氣:“原來是場噩夢啊……” “哼掷漱!你這毒婦竟也來了?” 一聲冷哼從身側響起榄檬,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤卜范,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鹿榜,有當地人在樹林里發(fā)現(xiàn)了一具尸體海雪,經...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年舱殿,在試婚紗的時候發(fā)現(xiàn)自己被綠了奥裸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡沪袭,死狀恐怖湾宙,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤侠鳄,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布埠啃,位于F島的核電站,受9級特大地震影響伟恶,放射性物質發(fā)生泄漏碴开。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一博秫、第九天 我趴在偏房一處隱蔽的房頂上張望潦牛。 院中可真熱鬧,春花似錦挡育、人聲如沸巴碗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽良价。三九已至寝殴,卻和暖如春蒿叠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚣常。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工市咽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抵蚊。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓施绎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贞绳。 傳聞我的和親對象是個殘疾皇子谷醉,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內容