Django2 Web 實戰02-用戶註冊登陸退出

做者:Hubery 時間:2018.9.14html

接上文:Django2 Web實戰01-啓動項目-model 擴展java

上一節中,咱們建立了工程,且建立了core應用以及core的相關models(Movie,Person)。 接下來咱們在這基礎上繼續完善:python

  • 用戶註冊/登錄/登出

1. 建立user應用

這裏,建立一個新的Django app:user,將其註冊到工程裏,用來管理用戶。 咱們儘可能那個讓user app複用。web

1.1 建立一個Django的app

命令行建立user數據庫

cd MyMovie
python manage.py startapp user
複製代碼

註冊到Django工程裏 MyMovie/settings.pydjango

INSTALLED_APPS = [
    'user',  # 必須在admin以前
    'core',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
複製代碼

注: 將咱們的app放到Django自帶的app以前註冊,是個好習慣。 Django的內建app:auth,爲咱們提供了一個可用的user模型。數組

1.2 建立一個註冊視圖

建立視圖以前,先建立一個自定義的表單:UserForm,包含幾個註冊內容:username/first_name/last_name/password/email,這應該算是一個用戶最基本的信息了; 好 user/forms.py,若是沒有forms.py文件,就地建立:瀏覽器

from django import forms
from django.contrib.auth.models import User

class UserForm(forms.ModelForm):
    username = forms.CharField(widget=forms.TextInput({
                'class': 'form-control',
                'placeholder': '請輸入用戶名'}))
    first_name = forms.CharField(widget=forms.TextInput({
            'class': 'form-control',
            'placeholder': '請輸入名字'}))
    last_name = forms.CharField(widget=forms.TextInput({
            'class': 'form-control',
            'placeholder': '請輸入姓氏'}))
    password = forms.CharField(widget=forms.PasswordInput({
            'class': 'form-control',
            'placeholder': '請輸入密碼'}))
    email = forms.CharField(widget=forms.TextInput({
            'class': 'form-control',
            'placeholder': '請輸入郵箱'}))

    class Meta:
        model = User
        fields = ('username',
                  'first_name',
                  'last_name',
                  'email',
                  'password')
複製代碼

RegisterView類可讓用戶在咱們的網站上註冊。重寫get post函數,處理註冊成功/失敗的狀況。 user/views.pybash

from django.contrib.auth.models import User
from django.shortcuts import render
from django.views.generic import View
from user.forms import UserForm

# 註冊視圖
class RegisterView(View):
    form_class = UserForm  # 上文自定義的表單
    template_name = 'user/register.html'

    # 顯示空表單
    def get(self, request):
        form = self.form_class(None)
        return render(request, self.template_name, {'form': form})

    # 處理POST表單數據
    def post(self, request):
        form = self.form_class(request.POST)
        if form.is_valid():
            user = User.objects.create_user(
                username=form.cleaned_data['username'],
                first_name=form.cleaned_data['first_name'],
                last_name=form.cleaned_data['last_name'],
                email=form.cleaned_data['email'],
                password=form.cleaned_data['password'],
            )
            # 保存到數據庫中
            user.save()
            # 註冊成功以後 跳轉到成功頁面
            return render(request, 'user/register_success.html', {'form': form})
        return render(request, self.template_name, {'form': form})
複製代碼
  • RegisterView繼承了View,須要重寫GET/POST方法。session

  • template_name = 'user/register.html',這是將要建立的模版。它的context與以前見過的稍微有些不一樣;它沒有objectobject_list變量,但有個form變量,這個變量是一個類實例,咱們在form_class屬性中設置的。

  • form_class = UserForm,這就是View要用的form類。簡單的模型能夠直接設置model = MyModel,但一個user模型比較複雜,不能直接這麼設置。這個問題能夠後續詳述。

  • 若是View接收到一個GET請求,它會給form渲染一個空模版。

  • 若是View接收到一個POST請求,一樣會經過self.form_class(request.POST)來建立form實例。若是該form有效:form.is_valid(),則根據form中用戶輸入的數據來建立用戶,並保存到數據庫中,同時渲染出建立成功的模版。

1.3 建立註冊視圖對應的模版

寫模版前咱們要知道,Django沒有提供<form>或者<button type='submit'>之類的tag,只是提供了form的內容。這讓咱們能夠在同一個<form>中包含多個Django表單。 添加一個模版:必須遵循路徑和命名規範,以前講過。 user/templates/user/register.html

{% extends 'base.html' %}
{% block main %}
    <h1>註冊MyMovie</h1>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit" >
            註冊
        </button>
    </form>
{% endblock %}
複製代碼

user/templates/user/register_success.html

{% extends 'base.html' %}
{% block main %}
    <div class='create-account-msg-container'>
        <div class='circle'>
            <i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
        </div>
        <h3>帳戶已成功註冊!</h3>
        <a href="{% url 'user:login' %}">點擊登錄</a>
    </div>
{% endblock %}
複製代碼

這兩個模版與以前的模版同樣,繼承base.html,將代碼寫在已經存在的block中。 當一個模版渲染出來,將被渲染成兩部分,第一部分是可選的tag,<ul class='errorlist'>用來生成錯誤信息,而後每一個字段都被渲染成4個基本的部分:

  • <label>tag 顯示字段名字
  • <ul class='errorlist'>tag 顯示用戶以前提交的錯誤信息,只有出錯的時候纔會顯示
  • <input>或者<select>tag 接收用戶輸入
  • <span class='helptext'>tag 顯示幫助信息

Form附帶了如下三個工具方法來渲染form:

  • as_table(),每一個字段都包含在<tr>tag中,標籤在<th>tag中,控件包含在<td>tag中。沒有提供<table>tag。
  • as_ul,整個字段(label和幫助widget)都包含在<li>tag中。沒有提供<ul>tag。
  • as_p, 整個字段包含在<p>tag中。

不提供<table>和<ul> tag的form,不提供<form> tag,以便在必要的時候輸出多個form。

上面代碼中,咱們用了as_p()方法,由於咱們不須要很細粒度的佈局控制,稍微顯示下就好。 第一次在模版中使用csrf_token的tag。CSRF是web應用的常見漏洞,後續會提到。Django會自動檢查全部POST/GET請求是否具備有效的csrfmiddlewaretokenheader。若是請求中缺失這些信息,則該請求不會到達視圖,返回一個403 Forbidden

已經有了模版,接下來在URLConf中添加一個path()對象來配置咱們的視圖。

1.4 給RegisterView添加一個path

user應用下沒有urls.py文件,要手動建立user/urls.py

from django.urls import path
from user import views

app_name = 'user'
urlpatterns = [
    path('register/', views.RegisterView.as_view(), name='register'),
]
複製代碼

而後在根URLConf中包含這個URLConf: MyMovie/urls.py

from django.contrib import admin
from django.urls import path, include

import core.urls
import user.urls

urlpatterns = [
    path('admin/', admin.site.urls),
    path('user/', include(user.urls, namespace='user')),
    path('', include(core.urls, namespace='core')),
]
複製代碼

寫完RegisterView,模版,以及將RegisterView註冊到工程後,瀏覽器:

http://127.0.0.1:8000/user/register/
複製代碼

用戶註冊UI及數據庫寫入見截圖:

註冊頁面

註冊成功查看數據庫

注:因爲URLConf只會在找到第一個匹配path以前進行搜索,匹配成功以後的URL再也不處理。因此咱們儘可能把沒有前綴或者通用的URLConfs的path放到最後,這樣就不會意外阻止其餘的視圖的加載。若是把沒有前綴的path放到最前面,可能會致使意外狀況出現,不執行後續配置的path。

1.5 登錄登出

Django的auth應用提供了登錄/登出視圖。集成須要兩步:

  • 將登錄/登出視圖註冊到user的URLConf中;
  • 給登錄/登出視圖添加模版

1.5.1 更新user的URLConf

Django的auth應用提供了不少視圖來簡化用戶管理和驗證,包括登錄登出,更改密碼,找回密碼等。一個功能齊全的產品的用戶模塊,至少提供這3個功能。這裏呢,咱們簡化一下,只用到登錄/登出。

更新下user/urls.py來使用auth應用的登錄/登出功能:

from django.urls import path
from user import views
from django.contrib.auth import views as auth_views

app_name = 'user'
urlpatterns = [
    path('register/', views.RegisterView.as_view(), name='register'),
    path('login/', auth_views.LoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]
複製代碼

注: 若是你就要想提供auth應用提供的全部視圖,那你能夠這麼配置URLConf:

from django.contrib.auth import urls
app_name = 'user'
urlpatterns = [
	path('', include(urls)),
]
複製代碼

相似於java的導包, import *; 不要前綴,一鍵導入,不建議這麼作,可能會有問題,最好是用到哪一個註冊哪一個。

1.5.2 建立LoginView模版

建立一個模版 user/templates/registration/login.html

{% extends 'base.html' %}
{% block title %}
    登錄 - {{ block.super }}
{% endblock %}
{% block main %}
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button class="btn btn-primary">
            登錄
        </button>
    </form>
{% endblock %}
複製代碼

這個代碼是否是和user/register.html很像? 對比下看看?

{% extends 'base.html' %}
{% block main %}
    <h1>註冊MyMovie</h1>
    <form method="post">
        {{ form.as_p }}
        {% csrf_token %}
        <button type="submit" class="btn btn-primary">
            註冊
        </button>
    </form>
{% endblock %}
複製代碼

瀏覽器中輸入:

http://127.0.0.1:8000/user/login/
複製代碼

顯示截圖:

登錄頁面

嗯,那麼問題來了,若是登錄成功了,跳哪兒去?

1.5.3 登錄成功的跳轉

RegisterView中,咱們能夠指定登錄成功以後往哪兒跳。LoginView類能夠經過如下幾個步驟來決定往哪兒跳:

  • 若是URL有效,用POST的參數next,指向託管此應用的server。path()的名字不可用。
  • 若是URL有效,用GET的參數next,執行託管此應用的server。path()的名字不可用。
  • LOGIN_REFIRECT_URL有個默認設置'/accounts/profile/'。path()的名字可用。

咱們這裏,登錄成功以後都跳轉到movie列表,那麼咱們更新MyMovie/settings.py文件添加一個LOGIN_REFIRECT_URL設置:

LOGIN_REDIRECT_URL = 'core:MovieList'
複製代碼

配置好登錄成功後到跳轉頁,看截圖:

登錄成功跳轉列表

然而,有這麼種狀況,若是想讓用戶跳轉到指定的頁面,咱們能夠用next參數來指定跳轉頁。如用戶在登陸以前要嘗試執行某些操做,咱們會將登錄前所在的頁面做爲一個next參數傳遞給LoginView,以便登錄成功以後再重定向回來。 即:訪問設備列表->跳轉到登錄頁->登錄成功後->重定向回設備列表。

1.5.4 建立一個登出模版

這個LogoutView比較直接。當收到GET請求,會推出用戶登錄而後嘗試渲染registration/logged_out.html。

{% extends 'base.html'%}
{% block title %}
    登出
{% endblock %}
{% block main %}
    <h1>登出</h1>
    <p>自定義登出模版</p>
{% endblock %}
複製代碼

GET請求能修改用戶的狀態,這很不尋常,因此值得記住這個視圖LogoutView的不一樣之處。 LogoutView還有另一個不尋常的地方,若是你沒提供registration/logged_out.html模版,同時你在settings.py中已經註冊了admin應用,那麼Django可能會使用admin應用中自帶的模版。 見截圖:

退出頁面

Django將模版名稱解析爲文件的方式,要經歷3步,一旦找到文件就會中止解析,以下:

  • Django迭代settings.TEMPLATES數組下的DIRS目錄;
  • 若是APP_DIRSTrue,那麼Django會迭代INSTALLED_APPS目錄,直到找到匹配的爲止。若是INSTALLED_APPS列表的註冊應用admin在user以前,那麼admin會優先被匹配到;若是user在admin以前,那麼user優先被匹配。
  • 若是沒找到,會拋出一個異常:TemplateDoesNotExist

這就是爲啥咱們將user放到admin以前,且添加了註釋,以便警告後續的接手人員不要改變註冊的先後順序。

1.6 user小結

咱們建立了user應用,來封裝用戶管理。在user應用中,咱們使用了很多Django內置應用auth提供的功能,包括:UserCreationFormLoginViewLogoutView等。咱們也學習了下如何建立新的Django提供的視圖,用CreateViewUserCreationForm組合起來建立一個RegisterView視圖。

既然有了用戶,那麼就可讓他們來給movies進行投票了。

Django2 Web 實戰03-文件上傳

天星技術團QQ:557247785

歡迎來擾
相關文章
相關標籤/搜索