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)

python代码

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>

index.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>

login.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)

app.py

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)

测试form框架

  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)

python代码

<!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('', 'fury@163.com', '', 'fury'),
User('', 'zeus@163.com', '', 'zeus'),
User('', 'warrior@163.com', '', '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 项目改进

  获取源代码:点击前往

    

      

Flask10 登录模块、表单框架、表单渲染、表单验证、bookie、请求之前钩子、g对象、编写装饰器的更多相关文章

  1. flask框架(七)——蓝图、请求上下文、g对象、信号、flask_session

    蓝图 作用:对程序进行目录结构划分 不使用蓝图情况下,自己分文件 目录结构: -templates -views -__init__.py -user.py -order.py -app.py app ...

  2. 登录模块(前端bookstrapValidator校验+加密+后台加密+后台验证)

    package sysone.zr.com.controller; import java.io.IOException; import javax.servlet.http.HttpServletR ...

  3. 什么是CSRF跨站请求伪造?(from表单效验csrf-ajdax效验csrf-Ajax设置csrf-CBV装饰器验证csrf)

    目录 一:csrf跨站请求伪造 1.什么是CSRF? 2.CSRF攻击案例(钓鱼网站) 3.钓鱼网站 内部原理 4.CSRF原理(钓鱼网站内部本质) 5.从上图可以看出,要完成一次CSRF攻击,受害者 ...

  4. python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化

    生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...

  5. 【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--目录(8/8 完结)

    为什么要做这个 在使用nodejs开发过程中,总是发现需要做很多重复性的体力劳动,且因为自身是服务端程序员出身,感觉有一些服务端好的东西其实可以在nodejs上得到应用并能提高一些开发工作效率. 本系 ...

  6. python 用装饰器写登录

    # 1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件), # 要求登录成功一次,后续的函数都无需再输入用户名和密码 # FLAG = False # def login(func): ...

  7. 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...

  8. MySQL:记录的增删改查、单表查询、约束条件、多表查询、连表、子查询、pymysql模块、MySQL内置功能

    数据操作 插入数据(记录): 用insert: 补充:插入查询结果: insert into 表名(字段1,字段2,...字段n) select (字段1,字段2,...字段n) where ...; ...

  9. DWZ框架Ajax无刷新表单提交处理流程

    DWZ框架Ajax无刷新表单提交处理流程是: 1.       ajax表单提交给服务器 2.       服务器返回一个固定格式json结构 3.       js会调函数根据这个json数据做相应 ...

随机推荐

  1. 使用MAVEN手动创建web项目

    问题:如下图,使用maven创建webapp项目时,默认使用maven-archetype-webapp这个archetype,由于这个archetype比较古老,有如下缺点: 1. 默认生成的项目会 ...

  2. Android开发--多线程之Handler

    前言 Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不 允许Activity新启动的线程访问该Activity里的 ...

  3. C#判断VS是否处于设计模式

    public class CheckDesingModel { public static bool IsDesingMode() { bool ReturnFlag = false; if (Lic ...

  4. [MEF] 学习之一 入门级的简单Demo

    MEF 的精髓在于插件式开发,方便扩展. 我学东西,习惯性的先搞的最简单的Demo出来,看看有没有好玩的东东,然后继续深入.这个博文,不谈大道理,看demo说事儿. 至于概念,请google ,大把大 ...

  5. 20145229吴姗珊 《Java程序设计》第8周学习总结

    20145229吴姗珊 <Java程序设计>第8周总结 教材学习内容总结 第十四章 NIO与NIO2 NIO: InputStream.OutputStream的输入输出,基本上是以字节为 ...

  6. [算法]数组的partition调整

    题目一: 给定一个有序数组arr,调整arr使得这个数组的左半部分没有重复部分且升序,而不用保证右部分是否有序. 例如:arr=[1,2,2,2,3,3,4,5,6,6,7,7,8,8,9,9],调整 ...

  7. linux常见命令2

    systemctl set-hostname HOSTNAME  在centos7上设置主机名,永久有效 curl -O -L http://www.gnu.org/software/gettext/ ...

  8. fffmpeg 提取pcm

    ffmpeg -i input.aac -codec:a pcm_f32le -ar 48000 -ac 2 -f f32le output.pcm

  9. Android GreenDao 中文表名,中文字段DAO生成乱码的问题

    在gradle.properties 文件中加入编码类型 # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gr ...

  10. jQuery查找子元素与后代元素

    1. 子元素: $().children('选择器')  如选择type为file的子元素  $(this).children("input[type=file]") 或者 $(& ...