上面咱們的用戶登陸的方法是基於函數來作的。本節咱們作一個基於類方法的版本。
要求對類的繼承有了解。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": "用戶名或密碼錯誤! "})
繼承的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")
驗證最大長度,是否爲空等一系列。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": "用戶名或密碼錯誤! "})
好比:既然表單都驗證失敗了,就不用顯示密碼出錯了數據庫
# 僅當用戶真的密碼出錯時 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
時已經對於咱們的字段進行了驗證。
打上斷點:
debug
後f6
運行到
此時能夠看到errors(ErrorDict)
中的錯誤
將form傳回前端:
前端中取值:
給這個class加上errorput會顯示紅色外框。
注意:寫在class裏面
<div class="error btns login-form-tips" id="jsLoginTips"> {% for key, error in login_form.errors.items %} {{ error }} {% endfor %} {{ msg }}</div>
本小節完畢對應commit:
6-4 & 5 登陸換用類繼承view實現,使用Django form進行表單驗證並把錯誤信息提示到前臺。
咱們本節來說session和cookie
User1如何實現登陸的。
cookie是瀏覽器支持的一種本地存儲方式。以dict,鍵值對方式存儲。
{"sessionkey": "123"}
瀏覽器會自動對於它進行解析。
用戶向服務器發起的兩次請求之間是沒有狀態的。也就是服務器並不知道這是同一個用戶發的。
作到記住用戶:
瀏覽器a在向服務器發起請求,服務器會自動給瀏覽器a回覆一個id,瀏覽器a把id放到cookie當中,在下一次請求時帶上這個cookie裏的id值向瀏覽器請求,服務器就知道你是哪一個瀏覽器發過來的了。
服務器a
發回來的id
會放到服務器a
的域之下。不能跨域訪問cookie。
使用瀏覽器隨便打開一個網頁,而後f12
打開。
好比我使用的Chrome
瀏覽器
會找到存儲在瀏覽器本地的cookie值
點擊clear all
清空全部的cookie
f5
刷新頁面,會發現又把這些cookie值進來。
若是將用戶名和密碼直接保存在cookie,能夠實現最垃圾最簡略版本的自動登陸。
用戶在第一次請求後,瀏覽器回覆的id既能夠是用戶的user id。
也能夠一段任意的字符串,咱們把它叫作session id
根據用戶名和密碼,服務器會採用本身的規則生成session id
。這個session id
保存在本地cookie。瀏覽器請求服務器會攜帶。
session id
取出這些基本信息。Django的默認表中的session
表就記錄了用戶登陸時,後端咱們Django爲用戶生成的sessionid
。
能夠看到session key value
和過時時間。
咱們能夠清空這張表的數據。運行項目進行登陸。
能夠看到咱們剛剛生成的session id。
此時經過f12
查看瀏覽器在本地存儲的session id
。能夠看到以下圖和咱們數據庫中的一致。
session_key 發到瀏覽器叫作session id
經過session id 用戶訪問任何一個頁面都會攜帶,服務器就會認識。
Setting.py中,
這個app會攔截咱們每次的request請求,在request
中找到session id,而後去數據表中進行查詢。
而後經過session key
去找到session data
。此時直接爲咱們取出了user。
在服務器返回瀏覽器的response
中也會直接加上session id
cookie是瀏覽器本地存儲機制,存在域名之下,存儲不安全。
服務器在返回id時經過規則生成一串字符,並設置了過時時間。存儲在服務器端(數據庫)
users/views.py
# 註冊功能的view class RegisterView(View): # get方法直接返回頁面 def get(self, request): return render(request, "register.html", {})
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" )
此時訪問首頁發現能夠成功跳轉到註冊頁面
他會自動根據setting中配置,爲咱們加上前綴
若是咱們把目錄在setting中改到mystatic。url中會自動添加指定的前綴
能夠看到能夠訪問成功。
枯燥可是要有耐心。
這時候訪問三個頁面,查看樣式是否無缺。
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
進入數據庫查看生成的表
users/forms.py:
# 引入驗證碼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
# 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})
找到上圖驗證碼部分。修改成下圖
Forms中的field會生成不一樣的框。
咱們只有label可是前端能夠查看到input框等,也就是Registerform會爲咱們生成輸入框+驗證碼。
隱藏的字符串的框會被帶到後臺,由Django爲咱們進行驗證。驗證該驗證碼是否保存過。
能夠看得咱們數據庫中將這個hashkey進行了保存。這個key與驗證碼內容對應。
後臺會把驗證碼值 和 hashkey進行聯合查詢。
users/views.py的RegisterView中添加post方法:
def post(self, request): # 實例化form register_form = RegisterForm(request.POST) if register_form.is_valid(): pass
修改form表單提交方式與提交到哪一個url
前端的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; }
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
上圖爲qq郵箱開啓smtp服務
點擊生成受權碼
def post中加上發送郵件
users/views.py
:
# 發送郵件 from utils.email_send import send_register_eamil # 發送註冊激活郵件 send_register_eamil(user_name, "register")
點擊註冊提交,由於咱們沒有return。一直在轉圈圈。
可是數據庫中已經添加了字段。
能夠看到咱們的郵件已經被髮送到郵箱中。
若是註冊成功返回login頁面:不成功,返回register頁面並報錯。
找貓畫虎:將login中的錯誤提示搬運到register中來。
若是傳回的有值則,顯示傳回來值。
密碼也作一樣操做
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中/$
表明以/$
爲結尾
其餘細節根據本身須要進行優化。
註冊功能製做完畢。對應commit:
註冊功能實現完畢,流程:註冊,發郵件,激活,登陸。對應6-6,7,8,9,10
原文學習來自簡書,做者:天涯明月笙連接:https://www.jianshu.com/p/9c621518d991