django+xadmin在線教育平臺(十二)

6-4 用form實現登陸-1

上面咱們的用戶登陸的方法是基於函數來作的。本節咱們作一個基於類方法的版本。
要求對類的繼承有了解。javascript

基礎教程中基本上都是基於函數來作的,其實更推薦基於類來作。基於類能夠帶來很多好處php

# 基於類實現須要繼承的view from django.views.generic.base import View class LoginView(View): # 直接調用get方法免去判斷 def get(self, request): # render就是渲染html返回用戶 # render三變量: request 模板名稱 一個字典寫明傳給前端的值 return render(request, "login.html", {}) def post(self, request): # 取不到時爲空,username,password爲前端頁面name值 user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") # 成功返回user對象,失敗返回null user = authenticate(username=user_name, password=pass_word) # 若是不是null說明驗證成功 if user is not None: # login_in 兩參數:request, user # 實際是對request寫了一部分東西進去,而後在render的時候: # request是要render回去的。這些信息也就隨着返回瀏覽器。完成登陸 login(request, user) # 跳轉到首頁 user request會被帶回到首頁 return render(request, "index.html") # 沒有成功說明裏面的值是None,並再次跳轉回主頁面 else: return render(request, "login.html", {"msg": "用戶名或密碼錯誤! "}) 
 
mark

繼承的view中的方法。html

django1.9.8 urls中的配置:前端

# 換用類實現 from users.views import LoginView # 基於類方法實現登陸,這裏是調用它的方法 url('^login/$', LoginView.as_view(), name="login") 

Django2.0.1 urls配置:java

# 基於類方法實現登陸,這裏是調用它的方法 path('login/', LoginView.as_view(), name="login") 

6-5 form字段驗證

驗證最大長度,是否爲空等一系列。python

users下新建forms文件。git

# encoding: utf-8 __author__ = 'mtianyan' __date__ = '2018/1/10 0010 04:44' # 引入Django表單 from django import forms # 登陸表單驗證 class LoginForm(forms.Form): # 用戶名密碼不能爲空 username = forms.CharField(required=True) password = forms.CharField(required=True, min_length=5) 

定義好forms以後咱們來使用它作驗證。github

def post(self, request): # 類實例化須要一個字典參數dict:request.POST就是一個QueryDict因此直接傳入 # POST中的usernamepassword,會對應到form中 login_form = LoginForm(request.POST) #is_valid判斷咱們字段是否有錯執行咱們原有邏輯,驗證失敗跳回login頁面 if login_form.is_valid(): # 取不到時爲空,username,password爲前端頁面name值 user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") # 成功返回user對象,失敗返回null user = authenticate(username=user_name, password=pass_word) # 若是不是null說明驗證成功 if user is not None: # login_in 兩參數:request, user # 實際是對request寫了一部分東西進去,而後在render的時候: # request是要render回去的。這些信息也就隨着返回瀏覽器。完成登陸 login(request, user) # 跳轉到首頁 user request會被帶回到首頁 return render(request, "index.html") # 驗證不成功跳回登陸頁面 # 沒有成功說明裏面的值是None,並再次跳轉回主頁面 else: return render(request, "login.html", {"msg": "用戶名或密碼錯誤! "}) 

完善錯誤提示

好比:既然表單都驗證失敗了,就不用顯示密碼出錯了數據庫

 
mark
# 僅當用戶真的密碼出錯時 else: return render(request, "login.html",{"msg":"用戶名或密碼錯誤!"}) # 驗證不成功跳回登陸頁面 # 沒有成功說明裏面的值是None,並再次跳轉回主頁面 else: return render( request, "login.html", { "login_form": login_form }) 

forms中的名稱username和password必須和html中的一致。畢竟他是使用的request.POST
而request是從前面傳過來的。django

實例化LoginView時已經對於咱們的字段進行了驗證。

打上斷點:

 
mark

debugf6運行到

 
mark

此時能夠看到errors(ErrorDict)中的錯誤

 
mark

將form傳回前端:

 
mark

前端中取值:

 
mark

給這個class加上errorput會顯示紅色外框。

 
mark

注意:寫在class裏面

將forms錯誤信息顯示出來

<div class="error btns login-form-tips" id="jsLoginTips"> {% for key, error in login_form.errors.items %} {{ error }} {% endfor %} {{ msg }}</div> 
 
mark
  • 寫了一個類繼承Django的view,而後寫了get post方法(get/post的if是Django替咱們完成的)
  • 在url中調用Loginview的as_view方法須要加上括號,進行調用。
  • Django的form進行表單驗證並把error值傳到前臺。
  • is_valid方法,驗證表單

本小節完畢對應commit:

6-4 & 5 登陸換用類繼承view實現,使用Django form進行表單驗證並把錯誤信息提示到前臺。

6-6 session和cookie自動登陸機制

咱們本節來說session和cookie

User1如何實現登陸的。

cookie的存儲

cookie是瀏覽器支持的一種本地存儲方式。以dict,鍵值對方式存儲。

{"sessionkey": "123"} 

瀏覽器會自動對於它進行解析。

http請求是一種無狀態的請求

用戶向服務器發起的兩次請求之間是沒有狀態的。也就是服務器並不知道這是同一個用戶發的。

作到記住用戶:

瀏覽器a在向服務器發起請求,服務器會自動給瀏覽器a回覆一個id,瀏覽器a把id放到cookie當中,在下一次請求時帶上這個cookie裏的id值向瀏覽器請求,服務器就知道你是哪一個瀏覽器發過來的了。

有狀態請求(cookie)

 
mark

服務器a發回來的id會放到服務器a的域之下。不能跨域訪問cookie。

使用瀏覽器隨便打開一個網頁,而後f12打開。

好比我使用的Chrome瀏覽器

 
mark

會找到存儲在瀏覽器本地的cookie值

 
mark

點擊clear all清空全部的cookie f5刷新頁面,會發現又把這些cookie值進來。

若是將用戶名和密碼直接保存在cookie,能夠實現最垃圾最簡略版本的自動登陸。

解決cookie放在本地不安全的問題(session)

用戶在第一次請求後,瀏覽器回覆的id既能夠是用戶的user id。
也能夠一段任意的字符串,咱們把它叫作session id

根據用戶名和密碼,服務器會採用本身的規則生成session id。這個session id保存在本地cookie。瀏覽器請求服務器會攜帶。

  • 輸入用戶名 & 密碼
  • 調用 login(), 後端程序會根據用戶名密碼生成session id。保存在數據庫中。
  • 用戶登陸以後,須要經過這個session id取出這些基本信息。
 
mark

Django的默認表中的session表就記錄了用戶登陸時,後端咱們Django爲用戶生成的sessionid

 
mark

能夠看到session key value 和過時時間。

咱們能夠清空這張表的數據。運行項目進行登陸。

 
mark

能夠看到咱們剛剛生成的session id。

此時經過f12查看瀏覽器在本地存儲的session id。能夠看到以下圖和咱們數據庫中的一致。

 
mark

session_key 發到瀏覽器叫作session id

經過session id 用戶訪問任何一個頁面都會攜帶,服務器就會認識。

Setting.py中,

 
mark

這個app會攔截咱們每次的request請求,在request中找到session id,而後去數據表中進行查詢。
而後經過session key 去找到session data。此時直接爲咱們取出了user。

在服務器返回瀏覽器的response中也會直接加上session id

cookie是瀏覽器本地存儲機制,存在域名之下,存儲不安全。
服務器在返回id時經過規則生成一串字符,並設置了過時時間。存儲在服務器端(數據庫)

文章: http://projectsedu.com/2016/10/17/django%E4%BB%8E%E8%AF%B7%E6%B1%82%E5%88%B0%E8%BF%94%E5%9B%9E%E9%83%BD%E7%BB%8F%E5%8E%86%E4%BA%86%E4%BB%80%E4%B9%88/

6-7 用戶註冊

拷貝註冊頁面進入template目錄

書寫咱們對應要處理的view(RegisterView)

users/views.py

# 註冊功能的view class RegisterView(View): # get方法直接返回頁面 def get(self, request): return render(request, "register.html", {}) 

配置對應的url

Django1.9.8 url配置以下:

from users.views import RegisterView # 註冊url url("^register/", RegisterView.as_view(), name="register"), 

Django2.0.1 url配置以下

from users.views import RegisterView # 註冊url path("register/", RegisterView.as_view(), name = "register" ) 

修改index頁面中註冊url

 
mark

此時訪問首頁發現能夠成功跳轉到註冊頁面

修改靜態文件中static目錄引用

關鍵步驟load staticfile

 
mark

而後修改路徑爲一個相對於static的相對路徑

 
mark

他會自動根據setting中配置,爲咱們加上前綴

 
mark

若是咱們把目錄在setting中改到mystatic。url中會自動添加指定的前綴

能夠看到能夠訪問成功。

 
mark

將目前的三個html中的靜態文件所有修改目錄

枯燥可是要有耐心。

這時候訪問三個頁面,查看樣式是否無缺。

驗證碼庫實現驗證碼

https://github.com/mbi/django-simple-captcha

安裝配置

workon mxonline3
pip install  django-simple-captcha
workon mxonline2
pip install  django-simple-captcha==0.4.6
  • Add captcha to the INSTALLED_APPS in your settings.py

  • Add an entry to your urls.py:

django1.9.8以下:

from django.conf.urls import url, include urlpatterns += [ url(r'^captcha/', include('captcha.urls')), ] 

django2.0.1以下;

# 驗證碼url path("captcha/", include('captcha.urls')) 
makemigrations
migrate
 
mark

進入數據庫查看生成的表

 
mark
 
mark

將驗證碼展現到頁面

users/forms.py:

定義咱們的register form:

# 引入驗證碼field from captcha.fields import CaptchaField # 驗證碼form & 註冊表單form class RegisterForm(forms.Form): # 此處email與前端name需保持一致。 email = forms.EmailField(required=True) # 密碼不能小於5位 password = forms.CharField(required=True, min_length=5) # 應用驗證碼 captcha = CaptchaField() 

users/views.py

在咱們的registerform中實例化並傳送到前端:

# form表單驗證 & 驗證碼 from .forms import LoginForm, RegisterForm # 註冊功能的view class RegisterView(View): # get方法直接返回頁面 def get(self, request): # 添加驗證碼 register_form = RegisterForm() return render(request, "register.html", {'register_form':register_form}) 

前端獲取驗證碼值

 
mark
 
mark

找到上圖驗證碼部分。修改成下圖

 
mark

Forms中的field會生成不一樣的框。

 
mark

咱們只有label可是前端能夠查看到input框等,也就是Registerform會爲咱們生成輸入框+驗證碼。

隱藏的字符串的框會被帶到後臺,由Django爲咱們進行驗證。驗證該驗證碼是否保存過。

 
mark

能夠看得咱們數據庫中將這個hashkey進行了保存。這個key與驗證碼內容對應。

後臺會把驗證碼值 和 hashkey進行聯合查詢。

編寫register view的後臺邏輯(RegisterView)

users/views.py的RegisterView中添加post方法:

def post(self, request): # 實例化form register_form = RegisterForm(request.POST) if register_form.is_valid(): pass 
 
mark
 
mark

修改form表單提交方式與提交到哪一個url

 
mark

前端的form提交加上對應的crsf token

刷新驗證碼是前端幫咱們完成的:

//刷新驗證碼 function refresh_captcha(event){ $.get("/captcha/refresh/?"+Math.random(), function(result){ $('#'+event.data.form_id+' .captcha').attr("src",result.image_url); $('#id_captcha_0').attr("value",result.key); }); return false; } 

獲取前端頁面值並封裝成一個user_profile對象,保存到數據庫。

from django.contrib.auth.hashers import make_password if register_form.is_valid(): user_name = request.POST.get("email", "") pass_word = request.POST.get("password", "") # 實例化一個user_profile對象,將前臺值存入 user_profile = UserProfile() user_profile.username = user_name user_profile.email = user_name # 加密password進行保存 user_profile.password = make_password(pass_word) user_profile.save() pass 

發送郵件實現

setting中配置;

# 發送郵件的setting設置 EMAIL_HOST = "smtp.qq.com" EMAIL_PORT = 25 EMAIL_HOST_USER = "mxonline.mtianyan.cn" EMAIL_HOST_PASSWORD = " " EMAIL_USE_TLS= True EMAIL_FROM = "mxonline.mtianyan.cn" 

新建package後新建文件。

apps:utils/email_send.py:

# encoding: utf-8 from random import Random __author__ = 'mtianyan' __date__ = '2018/1/10 0010 20:47' from users.models import EmailVerifyRecord # 導入Django自帶的郵件模塊 from django.core.mail import send_mail # 導入setting中發送郵件的配置 from Mxonline2.settings import EMAIL_FROM # 生成隨機字符串 def random_str(random_length=8): str = '' # 生成字符串的可選字符串 chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789' length = len(chars) - 1 random = Random() for i in range(random_length): str += chars[random.randint(0, length)] return str # 發送註冊郵件 def send_register_eamil(email, send_type="register"): # 發送以前先保存到數據庫,到時候查詢連接是否存在 # 實例化一個EmailVerifyRecord對象 email_record = EmailVerifyRecord() # 生成隨機的code放入連接 code = random_str(16) email_record.code = code email_record.email = email email_record.send_type = send_type email_record.save() # 定義郵件內容: email_title = "" email_body = "" if send_type == "register": email_title = "mtianyan慕課小站 註冊激活連接" email_body = "請點擊下面的連接激活你的帳號: http://127.0.0.1:8000/active/{0}".format(code) # 使用Django內置函數完成郵件發送。四個參數:主題,郵件內容,從哪裏發,接受者list send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 若是發送成功 if send_status: pass 
 
mark

上圖爲qq郵箱開啓smtp服務

點擊生成受權碼

 
mark

def post中加上發送郵件

users/views.py

# 發送郵件 from utils.email_send import send_register_eamil # 發送註冊激活郵件 send_register_eamil(user_name, "register") 

點擊註冊提交,由於咱們沒有return。一直在轉圈圈。

可是數據庫中已經添加了字段。

 
mark

能夠看到咱們的郵件已經被髮送到郵箱中。

若是註冊成功返回login頁面:不成功,返回register頁面並報錯。

完善錯誤提示。

找貓畫虎:將login中的錯誤提示搬運到register中來。

  • register_form的報錯信息。
 
mark
 
mark
  • 郵箱 & 密碼 form驗證
 
mark

完善用戶值回填邏輯

 
mark

若是傳回的有值則,顯示傳回來值。

密碼也作一樣操做

修改默認的激活狀態爲false

post方法中

# 默認激活狀態爲false user_profile.is_active = False 

書寫處理激活的view。

# 激活用戶的view class ActiveUserView(View): def get(self, request, active_code): # 查詢郵箱驗證記錄是否存在 all_record = EmailVerifyRecord.objects.filter(code = active_code) # 激活form負責給激活跳轉進來的人加驗證碼 active_form = ActiveForm(request.GET) # 若是不爲空也就是有用戶 if all_record: for record in all_record: # 獲取到對應的郵箱 email = record.email # 查找到郵箱對應的user user = UserProfile.objects.get(email=email) user.is_active = True user.save() # 激活成功跳轉到登陸頁面 return render(request, "login.html", ) # 本身瞎輸的驗證碼 else: return render(request, "register.html", {"msg": "您的激活連接無效","active_form": active_form}) 

配置用戶激活的url並經過url提取到變量:

django1.9.8:

# 激活用戶url url(r'^active/(?P<active_code>.*)/$',ActiveUserView.as_view(), name= "user_active") 

django2.0.1:

# 激活用戶url re_path('active/(?P<active_code>.*)/', ActiveUserView.as_view(), name= "user_active") 

這裏經過?p將後面.*表明所有提取的正則,符合的內容傳入參數active_code中/$表明以/$爲結尾

 
mark

其餘細節根據本身須要進行優化。

註冊功能製做完畢。對應commit:

註冊功能實現完畢,流程:註冊,發郵件,激活,登陸。對應6-6,7,8,9,10

原文學習來自簡書,做者:天涯明月笙連接:https://www.jianshu.com/p/9c621518d991

相關文章
相關標籤/搜索