Flask开发项目结构:
2.程序经常需要多个配置,一般分为开发,测试和生产环境,他们使用不同的数据库,不会彼此影响。
3.程序工厂函数
(1)为什么需要程序工厂函数?
在单个文件中开发程序很方便,但却有个很大的缺点,因为程序在全局作用域中创建,所以无法动态修改配置。运行脚本时,程序实例已经创建,再修改配置为时已晚。这一点对单元测试尤其重要,因为有时为了提 高测试覆盖度,必须在不同的配置环境中运行程序。
这个问题的解决方法是延迟创建程序实例,把创建过程移到可显式调用的工厂函数中。这种方法不仅可以 给脚本留出配置程序的时间,还能够创建多个程序实例。
(2).如何使用程序工厂函数
创建扩展类时不向构造函数传入参数, 在之前创建的扩展对象上调用 init_app() 可以完成初始化过 程。
不适用程序工厂函数
app = Flask(name)
bootstrap = Bootstrap(app)
mail = Mail(app)
使用程序工厂函数
bootstrap = Bootstrap()
mail = Mail()
def create_app():
app = Flask(__name__)
bootstrap.init_app(app)
mail.init_app(app)
return app
4.蓝图:组件化开发
(1).什么是蓝图?
Flask蓝图提供了模块化管理程序路由的功能,使程序结构清晰、简单易懂。
假如说我们要为某所学校的每个人建立一份档案,一个很自然的优化方式就是这些档案如果能分类管 理,就是说假如分为老师、学生、后勤人员等类别,那么后续查找和管理这些档案就方便清晰许多。 Flask的蓝图就提供了类似“分类”的功能。
(2)为什么使用蓝图?
将不同的功能模块化
构建大型应用
优化项目结构
增强可读性,易于维护
(3).应用蓝图三部曲!!!!
5.启动脚本与依赖包文件
启动脚本:顶级文件夹中的 manage.py 文件用于启动程序。
app = create_app('default')
manager = Manager(app)
if __name__ == '__main__':
manager.run()
6.单元测试
(1).什么是单元测试?
单元测试也称之为“模块测试”,是对程序设计中的最小单元——函数进行测试的一种方法,所谓测试, 就是验证我们自己编写的方法能不能够得到正确的结果,即用方法得到的结果与真实结果进行比对,这 就称之为测试。
(2).如何实现单元测试
python中有特别多的单元测试框架和工具, unittest , testtools , subunit , coverage , testrepository , nose, mox , mock , fixtures , discover 等等,先不说如何写单元测试,光是怎 么运行单元测试就有N多种方法。 unittest ,作为标准python中的一个模块,是其它框架和工具的基 础。
(3).unittest核心概念及关系
7.Flask基本工作流程
(1).基本工作流程
(2).用户认证的逻辑关系
8.数据库模型要点
(1).对用户密码进行加密存储
Werkzeug 中的 security 模块能够很方便地实现密码散列值的计算。这一功能的实现只需要 两个函数,分别用在注册用户和验证用户阶段。
#对明文密码进行加密
generate_password_hash(password, method= pbkdf2:sha1 , salt_length=8) :密码加密 的散列值。
check_password_hash(hash, password) :密码散列值和用户输入的密码是否匹配.
9.Flask-Login优化数据库模型
用户登录程序后,他们的认证状态要被记录下来,这样浏览不同的页面时才能记住这个状态。Flask-Login 是个非常有用的小型扩展,专门用来管理用户认证系统中的认证状态,且不依赖特定的认证机制。
Flask-Login 提供了一个 UserMixin 类,包含常用方法的默认实现,且能满足大多数需求。
在init.py种关联app,model.py中继承UserMixin的类。
10.Flask-WTF表单(用于用户登录)
flask 中from.validate_on_submit()的作用
form.validate()在form.py中定义
form.py ----->views.py------>auth/register.html
在form.py中继承Flask-WTF中的FlaskForm表单类。
除了常规的验证函数,也可以自定义验证函数(验证用户名和邮箱是否已经注册[已经存在数据库中]),以validate_开头且跟着字段名的方法,这个方法和常规的验证函数一起调用。
在view.py中验证是否通过表单验证,若通过则将表单提交的数据写入数据库中。(先存入session缓存中,然后提交到数据库[实际只需要完成session操作,在config.py中已经定义自动提交])
(1).表单域类型
(2).常见验证规则
11.用户登录逻辑
在view.py的login视图函数中,判断用户是否存在并且密码是否正确(密码验证verify_password函数在model.py中),然后再缓存session
中存入用户的信息(以前用session,现在用Flask-longin中d的login_user,注销为logout_user),并redirect跳转到登录成功后的页面。
Flask-Login 提供的 @ login_required 修饰器会保护这个路由,因此,用户点击确认邮件中的链接后,要 先登录,然后才能执行这个视图函数
12.用户邮箱验证原理
(1).如何确认注册用户提供的信息是否正确?
常用方式是验证电子邮件地址。用户注册后,程序会立即发送一封确认邮件。新账户先被标记成待 确认状态,用户按照邮件中的说明操作后,才能证明自己可以被联系上。账户确认过程中,往往会要求 用户点击一个包含确认令牌的特殊 URL 链接。
(2).确认令牌的特殊 URL 链接该如何设计?
链 接 形 式是 http://www.example.com/auth/confirm/id , id 是用户的 id 。代表账户 id确认成功。
出现的问题: id可任意指定, 从而确认任意账户(不能避免暴力循环确认id)。
解决方法: id 进行安全加密后得到令牌。(把id加密成其他字符串)
(3)如何生成包含用户id的安全令牌?
itsdangerous 模块中的 TimedJSONWebSignatureSerializer 类生成具有过期时间的 JSON Web 签名( JSON Web Signatures,JWS )
from itsdangerous import TimedJSONWebSignatureSerializer
# 生成具有过期时间的 `JSON Web` 签名对象, # 1). westos是一个密钥,在 Flask 程序中可使用 SECRET_KEY 设置。 # 2). expires_in 参数设置令牌的过期时间,单位为秒。
s = TimedJSONWebSignatureSerializer('westos', expires_in = 3600)
# dumps() 方法为指定的数据生成一个加密签名,然后再对数据和签名进行序列化,生成令牌字符串。
token = s.dumps({ 'confirm': 23 }) # loads() 方法会检验签名和过期时间,如果通过,返回原始数据。否则抛出异常。
data = s.loads(token) # data = { 'confirm': 23 }
(4).邮箱验证数据库模型
模型中新加入了一个列confirmed用来保存账户的确认状态。 generate_confirmation_token() 方法生成一个令牌,有效期默认为一小时。.
confirm()方法检验令牌和检查令牌中id和已登录用户id是否匹配?
如果检验通过,则把新添加的 confirmed 属性设为 True
13.用户注册验证邮件的业务逻辑
当前的 /register 路由把新用户添加到数据库中后,会重定向到 /index。在重定向之前,这个路由需要发送 确认邮件。
send_mail.py -----> view.py ----->confirm.html
登录时发送确认邮件,发送邮件配置在config.py中,功能实现在seng_mail.py中(flask_mail导入Mail,Message),最后在view.py的register视图函数中实现邮件的发送,点击邮件中的链接定向到confirm.html模板(该模板在send_mail.py中定义),
——————————————————————————————
在confirm.html模板中定义用来确认的路由(名为confirm在view.py中),在confirm路由中判断该token信息是否与当前用户id一致(该逻辑代码在model.py中的confirm函数),若通过则跳转到todo.list,若不通过则返回到登录页面auth.login
14.Flask+uwsgi+Nginx+Centos部署
(1).uWSGI、uwsgi与WSGI
uWSGI是一个web服务器,它实现了WSGI协议、uwsgi协议、http协议等。
(C语言开发) uwsgi是一种线路协议而不是通信协议,常用于在uWSGI服务器与其他网络服务器的数据通信。
WSGI是一种Web服务器网关接口。它是一个Web服务器(uWSGI等服务器)与web应用(如用 Django/Flask框架写的程序)通信的一种协议。