Django2 Web 實戰02-使用者註冊登入退出

天星技術團隊發表於2018-09-14

作者:Hubery 時間:2018.9.14

接上文:Django2 Web實戰01-啟動專案-model 擴充套件

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

  • 使用者註冊/登陸/登出

1. 建立user應用

這裡,建立一個新的Django app:user,將其註冊到工程裡,用來管理使用者。我們儘量那個讓user app複用。

1.1 建立一個Django的app

命令列建立user

cd MyMoviepython manage.py startapp user複製程式碼

註冊到Django工程裡MyMovie/settings.py

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 formsfrom django.contrib.auth.models import Userclass 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.py

from django.contrib.auth.models import Userfrom django.shortcuts import renderfrom django.views.generic import Viewfrom 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方法。

  • 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 pathfrom user import viewsapp_name = 'user'urlpatterns = [    path('register/', views.RegisterView.as_view(), name='register'),]複製程式碼

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

from django.contrib import adminfrom django.urls import path, includeimport core.urlsimport user.urlsurlpatterns = [    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 pathfrom user import viewsfrom django.contrib.auth import views as auth_viewsapp_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 urlsapp_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

歡迎來擾

來源:https://juejin.im/post/5b9b8d6b5188255c877e337a

相關文章