
from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表單類去渲染模板時需要用到 from forms import LoginForm app = Flask(__name__) WTF(app) # 在app上注冊一個 WTF (所有的flask插件都必須進行注冊) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET請求') liginForm = LoginForm() # 相當於java中利用無參構造器創建對象 return render_template('login.html', loginForm = liginForm) if request.method == 'POST': print('POST請求') loginForm = LoginForm(request.form) # 相當於java中利用有參構造器創建對象 print(loginForm) email = loginForm.email.data password = loginForm.password.data print("郵箱為:{},密碼為:{}".format(email, password)) if loginForm.validate(): return render_template('index.html') else: return '表單驗證失敗,錯誤信息 -> ' + str(loginForm.errors) print(app.url_map) if __name__ == '__main__': app.run(debug=True)
1 一個請求路徑怎么實現兩個邏輯功能
實例:登錄模塊
進入登錄頁面和點擊登錄的請求路徑都是一樣的,只不過他們的請求方式不一樣而已;這樣我們在后台就只需要寫一個視圖函數來實現兩個功能邏輯;進入登錄頁面的請求時GET請求,點擊登錄的請求是POST請求
2 后台如何利用一個視圖函數實現不同的邏輯
根據請求方式不同執行不同的邏輯
利用 request 對象的屬性來判斷請求方式
request.method 返回值時請求方式(GET/POST/HEAD/OPTIONS)
2.1 編寫一個簡單的登錄模塊
2.1.1 要求
去往登錄頁面和點擊登錄的路徑保持一致
后台利用一個視圖函數處理去往登錄頁面和點擊登錄按鈕的請求
如果是去往登錄頁面的請求就響應一個登錄頁面,如果是點擊登錄頁面的請求就響應一個主頁面並獲取相關的登錄數據
2.1.2 編寫連個HTML文件

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主頁面</title> </head> <body> <h2>庠序科技主頁面</h2> <hr /> <h4>Donot aim for your success if you really want it. Just stick to do what you love and believe in.</h4> </body> </html>

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登錄頁面</title> </head> <body> <h2>庠序科技登錄頁面</h2> <hr /> <div> <form action="/login/" method="post"> <div> <label for="email">郵箱:</label><input type="text" id="email" name="email" /> </div> <div> <label for="password">密碼:</label><input type="password" id="password" name="password" /> </div> <div> <button type="submit">登錄</button> </div> </form> </div> </body> </html>
2.1.3 編寫視圖函數

from flask import Flask from flask import request from flask import render_template from werkzeug.datastructures import ImmutableMultiDict app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET請求') return render_template('login.html') if request.method == 'POST': print('POST請求') formData = request.form print(type(formData)) print(formData) email = formData.get('email', 'null') password = formData['password'] print("郵箱數據為:{},密碼數據為:{}".format_map(email, password)) return render_template('index.html') print(app.url_map) if __name__ == '__main__': app.run(debug=True)
3 利用表單框架書寫表單
3.1 導入表單框架
pip3 install -i https://pypi.doubanio.com/simple/ flask-wtf
3.2 編寫表單類

from flask_wtf import FlaskForm from wtforms import Form from wtforms import StringField, BooleanField class LoginForm(Form): email = StringField() password = StringField() loginForm = LoginForm() # 實例化一個LoginForm對象 print(loginForm.password.label) print(loginForm.email.label) print(loginForm.email()) print(loginForm.data) print(loginForm.errors)
3.3 利用表單類去渲染模板
3.3.1 准備
從 flask_wtf 中導入 CSRFProtect
from flask_wtf import CSRFProtect as WTF # 利用表單類去渲染模板時需要用到
在 Flask對象 上注冊一個 CSRFProtect
WTF(app) # 在app上注冊一個 WTF (所有的flask插件都必須進行注冊)
修改 Flask對象 的配置文件使得 WTF_CSRF_ENABLED 失效
app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效)
config.py 文件中的信息為 WTF_CSRF_ENABLED = False
詳情請查看修改 Flask應用默認配置 先關內容
3.3.2 利用表單類渲染模板的步驟
》導入表單類
from forms import LoginForm
》創建一個表單類對象
liginForm = LoginForm()
》將這個表單對象傳到模板中去
render_template('login.html', loginForm = liginForm)
》利用表單對象的相關方法去渲染模板
{{ loginForm.email.label }}:{{ loginForm.email() }}
注意:loginForm.email.label 和 loginForm.email() 都是python表達式,他們的返回值是一個字符串

from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表單類去渲染模板時需要用到 from forms import LoginForm app = Flask(__name__) WTF(app) # 在app上注冊一個 WTF (所有的flask插件都必須進行注冊) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET請求') liginForm = LoginForm() return render_template('login.html', loginForm = liginForm) print(app.url_map) if __name__ == '__main__': app.run(debug=True)

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登錄頁面</title> </head> <body> <h2>庠序科技登錄頁面</h2> <hr /> <div> <form action="/login/" method="post"> <div> {{ loginForm.email.label }}:{{ loginForm.email() }} </div> <div> {{ loginForm.password.label }}:{{ loginForm.password() }} </div> <div> <button type="submit">登錄</button> </div> </form> </div> </body> </html>
3.4 利用表單類獲取數據

from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表單類去渲染模板時需要用到 from forms import LoginForm app = Flask(__name__) WTF(app) # 在app上注冊一個 WTF (所有的flask插件都必須進行注冊) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET請求') liginForm = LoginForm() # 相當於java中利用無參構造器創建對象 return render_template('login.html', loginForm = liginForm) if request.method == 'POST': print('POST請求') loginForm = LoginForm(request.form) # 相當於java中利用有參構造器創建對象 print(loginForm) email = loginForm.email.data password = loginForm.password.data print("郵箱為:{},密碼為:{}".format(email, password)) return render_template('index.html') print(app.url_map) if __name__ == '__main__': app.run(debug=True)
3.5 如何利用表單框架去驗證獲取到的表單數據格式
3.5.1 在表單中為每個字段定義驗證器

from flask_wtf import FlaskForm from wtforms import Form from wtforms import StringField, BooleanField # 導入用到的字段 from wtforms.validators import InputRequired, Length, Email # 導入用到的驗證器 class LoginForm(FlaskForm): # 注意如果單獨使用功能時要繼承Form,如果在Flask框架中使用是要繼承FlaskForm email = StringField( label='郵箱', # 修改渲染時的value值 validators=[ # 設定字段驗證器 InputRequired('郵箱是必填項'), Email('郵箱格式錯誤') ] ) password = StringField( label='密碼', validators=[ InputRequired('密碼為必填項'), Length(6, 9, '密碼長度為6到9') ] ) # loginForm = LoginForm() # 實例化一個LoginForm對象 # print(loginForm.password.label) # print(loginForm.email.label) # print(loginForm.email()) # print(loginForm.data) # print(loginForm.errors)
3.5.2 在視圖函數中利用表單對象去驗證表單對象中的數據是否有效
3.6 如何驗證表單數據的合法性
前提:已經從前端獲取到用戶數據的郵箱和密碼數據
思路:利用郵箱到數據庫查詢用戶信息,如果有先關數據說明郵箱數據有效;通過郵箱查詢到的用戶信息中的密碼數據和前端傳過來的密碼數據進行比較,如果相等就說明密碼數據有效
3.6.1 模擬一個數據模型來充當數據庫

class User: # 模擬用戶類 def __init__(self, id, email, password, name): self.id = id self.email = email self.password = password self.name = name def check_password(self, password): return self.password == password users = [ # 模擬用戶數據 User('1', 'fury@163.com', '111111', 'fury'), User('2', 'zeus@163.com', '222222', 'zeus'), User('3', 'warrior@163.com', '333333', 'warrior') ] # 根據用戶ID去獲取數據 def findById(userId): for user in users: if user.id == userId: return user else: return None # 根據用戶郵箱去獲取數據 def findByEmail(email): for user in users: if user.email == email: return user else: return None
3.6.2 調用相關方法判斷表單數據是否有效

from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表單類去渲染模板時需要用到 from forms import LoginForm from models import findByEmail, findById app = Flask(__name__) WTF(app) # 在app上注冊一個 WTF (所有的flask插件都必須進行注冊) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET請求') liginForm = LoginForm() # 相當於java中利用無參構造器創建對象 return render_template('login.html', loginForm = liginForm) if request.method == 'POST': print('POST請求') loginForm = LoginForm(request.form) # 相當於java中利用有參構造器創建對象 print(loginForm) if loginForm.validate(): email = loginForm.email.data password = loginForm.password.data print("郵箱為:{},密碼為:{}".format(email, password)) user = findByEmail(email) if user: if user.check_password(password): return render_template('index.html') else: return '密碼錯誤' else: return '該郵箱為注冊' else: return '表單驗證失敗,錯誤信息 -> ' + str(loginForm.errors) print(app.url_map) if __name__ == '__main__': app.run(debug=True)
3.7 如何實現在用戶登錄成功后進入主頁面,並顯示:歡迎XXX
如果從前端獲取到的登錄數據判斷為有效后,就將用戶的名字信息添加到主頁模板中,並渲染主頁模板;如果用戶沒有登錄就進入到主頁面時會有登錄和注冊兩個按鈕
3.8 如何實現當用戶成功登錄並進入主頁后,當客戶端下次再次訪問這也的時候服務器會知道該前端之前已經登錄過
思路:用戶數據驗證成功后,就將唯一識別用戶的信息存儲到客戶端的cookie中,當客戶端下次訪問服務器時機會攜帶這個cookie信息,服務器會根據這個cookie信息去判斷該客戶端是否登陸過,如果登陸過就進入主頁顯示“歡迎xxx”,否則就進入主頁提示用戶登錄
注意:可以根據用戶是否選擇來“記住我”來設置cookie的有效時間
3.8.1 數據驗證成功后就設置cookie
3.8.2 用戶進入主頁時會利用請求對象去獲取cookie數據,如果獲取到了就會在進入主頁后顯示為登錄狀態
注意:這里登錄成功后僅僅會提示登錄成功,並不會重定向到主頁面去(故:需要手動修改路徑才能到主頁面去,這里有待改進)
3.9 這么把請求之前的邏輯單獨羅列出來
思路:利用請求之前那個鈎子 @app.before_request 這個鈎子注釋的函數會在每個請求之前執行
3.10 g對象的妙用
每個請求對象都會有一個g對象,可以向g對象添加屬性,而且這g對象在這個請求路徑下的所有函數共享這個g對象
3.11 如果用戶在沒有登錄的情況下進入到主頁面后怎么強制返回到登錄頁面
思路:寫一個裝飾器,該裝飾器的功能是,如果進入主頁面時通過cookie數據能夠獲取到用戶數據就什么也不做,如果獲取不到就重定向到登錄頁面
4 項目信息
4.1 項目結構
4.2 項目源代碼
5 項目改進
獲取源代碼:點擊前往