django系列七:用戶註冊
前言
所有的web系統中,一般都會有一個註冊的功能。在Django這套web框架中,註冊其實挺好玩的,無論是從設計角度、業務解耦角度以及表單安全形度,設計的都是那麼完美。
框架結構整理
在開始代碼之前,因為後面會有很多的views,所以重構了一下目錄結構,主要是web項目,結構目錄如下:
這裡增加了一個route包,其中route主要對應的是所有的views的管理包,因為後面再講解的時候直接會在route中添加相應業務方面的視圖。
註冊流程
其實很多網站的註冊流程大體都是一樣,填寫基本信息--->提交表單--->資料庫保存數據--->發送郵件讓用戶驗證。該篇忽略發送郵件驗證環節。
然後先預覽下下註冊的表單結構,訪問 http://localhost:8080/web/register/
Form Class
平常的web開發中,針對一個表單,比如:登錄、註冊等等,都是相應的通過直接手寫Dom元素,像<div>、<input>等等,再加上css樣式、js輸入框的驗證等等,從而來構建一個滿足業務需求的表單。
其中Django提供了一系列工具和庫來幫助我們構建表單,以接受來自網站訪問者的輸入,然後處理和響應輸入。比如現在要準備創建一個用戶註冊的表單,通過Post提交表單內容完成註冊。
Form Class換句話說,建立一個對象,通過對象來定義一個表單中的控制項、驗證、提醒等信息。具體可以參考官方文檔。
RegisterForm
該系列django系列五:資料庫配置中定義了一個model,我們來進一步完善下,代碼如下:
路徑:/web/models/user_model.py
from mongoengine import *class Users(Document): #用戶名 user_name = StringField() #郵箱 email = EmailField() #密碼 password = StringField() #郵箱是否已驗證 is_active=BooleanField(default=False)
這個其實就是對應的資料庫中表的欄位(資料庫用的是mongodb)。
然後定義一個 RegisterForm類
路徑:/web/form/customer_form.py
from django import formsfrom ..models.user_model import Usersclass RegisterForm(forms.Form): user_name = forms.CharField( widget=forms.TextInput(attrs={class: form-control, placeholder: 用戶名, required: True})) email = forms.CharField(widget=forms.EmailInput( attrs={class: form-control, placeholder: 郵箱, required: True})) password = forms.CharField(widget=forms.PasswordInput( attrs={class: form-control, placeholder: 密碼, required: True})) confirm_password = forms.CharField(widget=forms.PasswordInput( attrs={class: form-control, placeholder: 確認密碼, required: True}))
這裡就是應用django的Form class,我們看到RegisterForm類繼承了forms.Form。然後user_name、email 、password、confirm_password 對應的就是後面模版html中的dom元素。
這裡都是手動進行操作來進行書寫的,但是Django每個版本的書寫方式不一樣(當前是1.11)可以根據具體版本進行重寫。
其中這裡的註冊為了好看,所以引用了Bootstrp樣式以及部分表單驗證。同時兩次輸入的密碼一致性校驗是通過Django的Form Validate來進行驗證的,在上面代碼的基礎上,增加密碼一致性的判斷:
def clean(self): cleaned_data = super(RegisterForm, self).clean() password = cleaned_data.get(password) confirm_password = cleaned_data.get(confirm_password) if password and confirm_password: if password != confirm_password: raise forms.ValidationError(u兩次密碼輸入不一致,請重新輸入)
在Django的Form中 擁有這個clean屬性,這裡是clean進行了重寫。另一個cleaned_data對象是來獲取Django的Form中的Field,換成HTML元素來說的話,就是get input的值。
因為Django提倡ModelForm的操作與映射,從而簡化了很多不必要的操作邏輯,然而該系列中應用的是mongoengie這套orm框架,所以為了繼承思想,我們把對model的save操作,也添加在RegisterForm中,作為一個屬性。
def save(self): user = Users() user.user_name = self.cleaned_data[user_name] user.email = self.cleaned_data[email] user.password = self.cleaned_data[password] user.save()
該方法大家一看就明白了,就是把註冊信息保存到資料庫中。好了,讓我們看下整體的RegisterForm的代碼:
from django import formsfrom ..models.user_model import Usersclass RegisterForm(forms.Form): user_name = forms.CharField( widget=forms.TextInput(attrs={class: form-control, placeholder: 用戶名, required: True})) email = forms.CharField(widget=forms.EmailInput( attrs={class: form-control, placeholder: 郵箱, required: True})) password = forms.CharField(widget=forms.PasswordInput( attrs={class: form-control, placeholder: 密碼, required: True})) confirm_password = forms.CharField(widget=forms.PasswordInput( attrs={class: form-control, placeholder: 確認密碼, required: True})) #驗證 def clean(self): cleaned_data = super(RegisterForm, self).clean() password = cleaned_data.get(password) confirm_password = cleaned_data.get(confirm_password) if password and confirm_password: if password != confirm_password: raise forms.ValidationError(u兩次密碼輸入不一致,請重新輸入) #保存到資料庫中 def save(self): user = Users() user.user_name = self.cleaned_data[user_name] user.email = self.cleaned_data[email] user.password = self.cleaned_data[password] user.save()
Views
現在Form有了,但是如何把這個Form以html的形式展示的模版中呢?其實很簡單,來看下views,因為模版都是靠views進行指定,然後找到並渲染。在/web/route目錄下增加 customer.py文件,即:/web/route/customer.py
from django.core.urlresolvers import reverse_lazy #引用Django FormViewfrom django.views.generic.edit import FormView #註冊表單from ..form.customer_form import RegisterFormclass RegisterView(FormView): template_name = customer/register.html form_class = RegisterForm success_url = reverse_lazy(login) def form_valid(self, form): form.save() return super(RegisterView, self).form_valid(form)
首先定義了一個RegisterView 類,並繼承了Django的FormView。然後聲明了template_name 模版。其中form_valid也是Form Class用來驗證所錄入的表單信息是否符合規則。其中 reverse_lazy(login)表示驗證成功後跳轉的視圖。然後把這個視圖增加下:
from django.shortcuts import render def login(request): context = {} return render(request, customer/login.html, context)
所以視圖的整體代碼:
from django.core.urlresolvers import reverse_lazyfrom django.views.generic.edit import FormViewfrom django.shortcuts import render from ..form.customer_form import RegisterFormclass RegisterView(FormView): template_name = customer/register.html form_class = RegisterForm success_url = reverse_lazy(login) def form_valid(self, form): form.save() return super(RegisterView, self).form_valid(form)def login(request): context = {} return render(request, customer/login.html, context)
這樣視圖定義好了,那麼下一步就該模版了
Templates
在目錄 /web/templates/customer/中增加 login.html、register.html
目錄結構如下:
然後更改register.html模版內容:
{% load staticfiles %}<head> <link href="{% static "web/vendors/css/font-awesome.min.css" %}" rel="stylesheet" /> <link href="{% static "web/vendors/css/simple-line-icons.min.css" %}" rel="stylesheet" /> <link href="{% static "web/css/style.css" %}" rel="stylesheet" /></head><body class="app flex-row align-items-center"> <div class="container"> <div class="row justify-content-center"> <div class="col-md-6"> <div class="card mx-4"> {% if form.non_field_errors %} <div class="messages"> <div class="alert alert-warning alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button> {{ form.non_field_errors }} </div> </div> {% endif %} <div class="card-body p-4"> <h1>註冊</h1> <p class="text-muted">創建帳號</p> <form action="" method=post> {% csrf_token %} <div class="input-group mb-3"> <span class="input-group-addon"><i class="icon-user"></i></span> {{form.user_name}} </div> <div class="input-group mb-3"> <span class="input-group-addon">@</span> {{form.email}} </div> <div class="input-group mb-3"> <span class="input-group-addon"><i class="icon-lock"></i></span> {{form.password}} </div> <div class="input-group mb-4"> <span class="input-group-addon"><i class="icon-lock"></i></span> {{form.confirm_password}} </div> <button type="submit" class="btn btn-block btn-success">提交</button> </form> </div> </div> </div> </div> </div> <!-- Bootstrap and necessary plugins --> <script src="{% static "web/vendors/js/jquery.min.js" %}"></script> <script src="{% static "web/vendors/js/popper.min.js" %}"></script> <script src="{% static "web/vendors/js/bootstrap.min.js" %}"></script> <script src="{% static "web/vendors/js/jquery.validate.min.js" %}"></script></body>
這樣模版定義好了,因為引用了是H5 bootstrap樣式,所以這裡解析的html直接為
{{form.user_name}}、{{form.email}}、{{form.password}}、{{form.confirm_password}}。如果不應用的話,可以直接試一下{{form}}再看下效果。模版配置好了,那下一不就是Url,讓我們看下Url的配置
Url
編輯/web/urls.py文件
from django.conf.urls import url from .route import customerurlpatterns = [ url(r^register/$, customer.RegisterView.as_view() , name=register), url(r^login/$,customer.login, name=login),]
訪問http://localhost:8080/web/register展示結果
可以手動測試下,直接提交,現在的驗證是jquery的驗證方式和樣式。
如果錄入不同的密碼,則顯示自定義的驗證:
進行提交後,則會跳轉到login頁面
然後看下登錄資料庫,我們查看下:
這就是剛才新增加的用戶。
附:
在該系列中,用到的知識點比較多,Django的Form Class、Modal Class、
Form Validate、Clean、FormView、Widget,具體可以參考官網的解說。
推薦閱讀:
※職位速遞:知名互聯網金融公司高級數據分析工程師(年薪30~50W)
※競品分析到底在分析什麼?
※20180226上周文章更新匯總
※數據分析基礎之Anaconda和Python
※【數據分析】中文筆記翻譯計劃順利結束