django+xadmin在线教育平台(十二)
6-4 用form實現登錄-1
上面我們的用戶登錄的方法是基于函數來做的。本節我們做一個基于類方法的版本。
要求對類的繼承有了解。
基礎教程中基本上都是基于函數來做的,其實更推薦基于類來做。基于類可以帶來不少好處
# 基于類實現需要繼承的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中的方法。
django1.9.8 urls中的配置:
# 換用類實現 from users.views import LoginView# 基于類方法實現登錄,這里是調用它的方法 url('^login/$', LoginView.as_view(), name="login")Django2.0.1 urls配置:
# 基于類方法實現登錄,這里是調用它的方法path('login/', LoginView.as_view(), name="login")6-5 form字段驗證
驗證最大長度,是否為空等一系列。
users下新建forms文件。
# 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之后我們來使用它做驗證。
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是從前面傳過來的。
實例化LoginView時已經對于我們的字段進行了驗證。
打上斷點:
markdebug后f6運行到
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取出這些基本信息。
Django的默認表中的session表就記錄了用戶登錄時,后端我們Django為用戶生成的sessionid。
mark可以看到session key value 和過期時間。
我們可以清空這張表的數據。運行項目進行登錄。
mark可以看到我們剛剛生成的session id。
此時通過f12查看瀏覽器在本地存儲的session id。可以看到如下圖和我們數據庫中的一致。
marksession_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# 注冊urlurl("^register/", RegisterView.as_view(), name="register"),Django2.0.1 url配置如下
from users.views import RegisterView# 注冊urlpath("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如下;
# 驗證碼urlpath("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找到上圖驗證碼部分。修改為下圖
markForms中的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_passwordif 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服務
點擊生成授權碼
markdef 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的報錯信息。
- 郵箱 & 密碼 form驗證
完善用戶值回填邏輯
mark如果傳回的有值則,顯示傳回來值。
密碼也做同樣操作
修改默認的激活狀態為false
post方法中
# 默認激活狀態為falseuser_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:
# 激活用戶urlurl(r'^active/(?P<active_code>.*)/$',ActiveUserView.as_view(), name= "user_active")django2.0.1:
# 激活用戶urlre_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
轉載于:https://www.cnblogs.com/xinjie57/p/9232627.html
總結
以上是生活随笔為你收集整理的django+xadmin在线教育平台(十二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openstack及组件简要介绍
- 下一篇: ACM-ICPC 2018 徐州赛区网络