flask框架詳解
https://www.cnblogs.com/sss4/p/8097653.html
前言:
Django:1个重武器,包含了web开发中常用的功能、组件的框架;(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....);
Tornado:2大特性就是异步非阻塞、原生支持WebSocket协议;
Flask:封装功能不及Django完善,性能不及Tornado,但是Flask的第三方开源组件比丰富;http://flask.pocoo.org/extensions/
Bottle:比较简单;
总结:
都不是我写的!!!不论优劣,不同的工具而已;
小型web应用设计的功能点不多使用Flask;
大型web应用设计的功能点比较多使用的组件也会比较多,使用Django(自带功能多不用去找插件);
如果追求性能可以考虑Tornado;
Flask的socket是基于Werkzeug 实现的,模板语言依赖jinja2模板,在使用Flask之前需要安装一下;
pip3 install flask #安装flask

from werkzeug.wrappers import Request, Response # Flask的socket使用werkzeug实现,所以要导入 werkzeug @Request.application def hellow(request):
return Response('Hello World') if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost',400,hellow)

Flask简单使用

from flask import Flask
app=Flask(__name__) #创建1个Flask实例
@app.route('/') #路由系统生成 视图对应url,1. decorator=app.route() 2. decorator(first_flask)
def first_flask(): #视图函数
return 'Hello World' #response
if __name__ == '__main__':
app.run() #启动socket

一、配置文件
app=Flask(__name__,template_folder='templates',static_url_path='/static/',static_path='/zhanggen')
模板路径: template_folder='templates'
静态文件路径:static_url_path='/static/'
静态文件引入别名:static_path='/zhanggen'
设置为调试环境:app.debug=True (代码修改自动更新)
设置json编码格式 如果为False 就不使用ascii编码:app.config['JSON_AS_ASCII']=False
设置响应头信息Content-Type app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" (注意 ;charset=utf-8)
二、路由系统
1.动态路由(url传参)
@app.route('/user/<name>')
@app.route('/post/<int:age>')
@app.route('/post/<float:salary>')
@app.route('/post/<path:path>')
2、指定允许的请求方法
@app.route('/login', methods=['GET', 'POST'])
3、通过别名反向生成url
4、通过app.add_url_rule()调用路由

#方式2通过app.add_url_rule()方法的方式调用路由
app=Flask(__name__) def first_flask():
return 'Hello World' app.add_url_rule(rule='/index/',endpoint='name1',view_func=first_flask,methods=['GET'])
#app.add_url_rule(rule=访问的url,endpoint=路由别名,view_func=视图名称,methods=[允许访问的方法])
if __name__ == '__main__':
app.run()

5、扩展路由功能:正则匹配url
如果需要一些复杂的匹配规则可以自定义正则匹配url
四、视图
1、给Flask视图函数加装饰器
注意如果要给视图函数加装饰器增加新功能,一点要加在路由装饰器下面,才会被路由装饰器装饰,才能生生成url关系;
2、request和response
a.请求相关信息
request.method: 获取请求方法
request.json
request.json.get("json_key"):获取json数据 **较常用
request.argsget('name') :获取get请求参数
request.form.get('name') :获取POST请求参数
request.form.getlist('name_list'):获取POST请求参数列表(多个)
request.values.get('age') :获取GET和POST请求携带的所有参数(GET/POST通用)
request.cookies.get('name'):获取cookies信息
request.headers.get('Host'):获取请求头相关信息
request.path:获取用户访问的url地址,例如(/,/login/,/ index/);
request.full_path:获取用户访问的完整url地址+参数 例如(/login/?age=18)
request.script_root: 抱歉,暂未理解其含义;
request.url:获取访问url地址,例如http://127.0.0.1:5000/?age=18;
request.base_url:获取访问url地址,例如 http://127.0.0.1:5000/;
request.url_root
request.host_url
request.host:获取主机地址
request.files:获取用户上传的文件
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename)) 直接保存
b、响应相关信息
return "字符串" :响应字符串
return render_template('html模板路径',**{}):响应模板
return redirect('/index.html'):跳转页面
响应json数据
方式1: return jsonify(user_list)
方式2:
return Response(data,mimetype="application/json;charset=utf-8",)
如果需要设置响应头就需要借助make_response()方法
from flask import Flask,request,make_response
response = make_response(render_template('index.html'))
response是flask.wrappers.Response类型
response.delete_cookie('key')
response.set_cookie('key', 'value')
response.headers['X-Something'] = 'A value'
return respons
3 、Flask之CBV视图
五、模板语言
Flask使用的是Jinja2模板,所以其语法和Django无差别(Django的模板语言参考Jinja2)
1.引用静态文件
方式1:别名引入
<link rel="stylesheet" href="/zhanggen/commons.css">
方式2:url_for()方法引入
<link rel="stylesheet" href="{{ url_for('static',filename='commons.css') }}">
2.模板语言引用上下文对象
变量
循环、索引取值
Flask的Jinjia2可以通过Context 把视图中的函数传递把模板语言中执行,这就是Django中的simple_tag和simple_fifter;
simple_tag(只能传2个参数,支持for、if)
simple_fifter(对参数个数无限制,不支持for、if)
3.wtform(flask表单验证插件)
3.0.简介
wtforms WTForms是一个支持多个web框架的form组件,主要对用户请求数据 进行表单验证。
3.1. 安装
pip install wtforms #安装wtfroms插件
3.2.简单使用
wtforms和Django自带的form验证插件功能相同,使用起来大同小异;
用户登录页面验证
用户注册页面验证
3.2.wtforms源码 猜想....
A.自动生成html标签
先来分析一下form验证类的结构

LoginForm类中包含了2个字段: name 和 pwd,而name / pwd字段 = 对象,所以LoginForm 类包含了2个对象;
如果实例化了obj=LoginForm() 就等于 在 这1个对象中嵌套了 2个对象;
前端使用Form验证插件:

那如果在前端for循环LoginForm对象,就等于调用LoginForm对象的__iter__方法,把每个字段(对象)封装的数据 返回
如果前端{{ obj }}= 直接调用了字段对象的__str__方法;

B.数据校验
后台定义好正则
用户发来数据
对数据进行校验
3.3.源码流程
生成HTML标签并显示
1.验证类(LogibForm)生成
1.1.由于 metaclass=FormMeta,所以LoginForm是由FormMeta创建的
1.2.执行FormMeta 的__init__方法,在LoginForm中添加2个静态字段
1.3.开始解释LoginForm中的 实例化字段对象name=simple.StringField()simple.PasswordField()
StringField/PasswordField开始实例化(提到实例化就应该想到:指定元类的__call__、自己/父类的__new__、__init__):
StringField/PasswordField是默认元类,自己没有__new__和__init__方法;
但父类Field类中有__new__方法,所以执行父类的__new__(Field.__new__)返回UnboundField对象
由于Field.__new__方法返回了 1个 UnboundField对象,来看 UnboundField的__init__方法
UnboundField的__init__方法在 UnboundField对象中封装了Field类的参数和计数器,所以现在LoginForml类中封装数据如下

"""
print(LoginForm.__dict__)
LoginForm ={
'__module__': '__main__',
'name': <1 UnboundField(StringField, (),{'creation_counter': 1, 'label': '用户名', 'validators': [<wtforms.validators.DataRequired object at 0x00000000037DAEB8>, <wtforms.validators.Length object at 0x000000000382B048>], 'widget': <wtforms.widgets.core.TextInput object at 0x000000000382B080>, 'render_kw': {'class': 'form-control'} })>,
'pwd': <2 UnboundField(PasswordField, (),{'creation_counter': 2,'label': '密码', 'validators': [<wtforms.validators.DataRequired object at 0x000000000382B0F0>, <wtforms.validators.Length object at 0x000000000382B128>, <wtforms.validators.Regexp object at 0x000000000382B160>], 'widget': <wtforms.widgets.core.PasswordInput object at 0x000000000382B208>, 'render_kw': {'class': 'form-control'}})>,
'__doc__': None,
'_unbound_fields': None,
'_wtforms_meta': None,
}
"""

启发:
不一定要把代码都写在当前类中,如过多个类和类之间有同性方法、属性可以抽出来集中到父类之中;子类继承父类所以子类实例化对象之后,继承享有2者的属性和方法;所以看源码遇到继承一点要注意 观察父类;
每个对象实例化(在排除MetaClass的情况下)都会执行 父类的__new__方法,再去执行__init__方法;而__new__实质性决定了实例化出来的对象是神马?
2.LoginForm实例化
谈到类实例化应该先检查该类是否指定了 Meta类,如果指定了Meta类, 就需要先执行 (指定元类的__call__、自己/父类的__new__、__init__)
21.执行FormMeta的__call__方法,赋值LoginForm的_unbound_fields 和 _wtforms_meta属性;
根据unbound对象的creation_counter属性对 LoginForm中的字段进行排序,并填充到 LoginForm的_unbound_fields属性中
根据 LoginForm的__mro__继承顺序:获取当前类(FormLogin)所有父类,并在每个父类中 提取Meta属性添加到列表,转成元组,最后创建Meta类让其继承,赋值LoginForm._wtforms_meta属性
执行完了指定元类 FormMeta.__call__()方法之后的LoginForm类中封装的数据

print(LoginForm.__dict__)
LoginForm ={
'__module__': '__main__',
'name': <1 UnboundField(StringField, (),{'creation_counter': 1, 'label': '用户名', 'validators': [<wtforms.validators.DataRequired object at 0x00000000037DAEB8>, <wtforms.validators.Length object at 0x000000000382B048>], 'widget': <wtforms.widgets.core.TextInput object at 0x000000000382B080>, 'render_kw': {'class': 'form-control'} })>,
'pwd': <2 UnboundField(PasswordField, (),{'creation_counter': 2,'label': '密码', 'validators': [<wtforms.validators.DataRequired object at 0x000000000382B0F0>, <wtforms.validators.Length object at 0x000000000382B128>, <wtforms.validators.Regexp object at 0x000000000382B160>], 'widget': <wtforms.widgets.core.PasswordInput object at 0x000000000382B208>, 'render_kw': {'class': 'form-control'}})>,
'__doc__': None, '_unbound_fields': [
(name, UnboundField对象(1,simple.StringField,参数)),
(pwd, UnboundField对象(2,simple.PasswordField,参数)),
],,
'_wtforms_meta': Meta(DefaultMeta)类,
}
"""

启发:
2.2.执行LoginForm的__new__方法
没有__new__方法 pass
2.3.执行LoginForm的__init__方法实例化form对象
执行Form父类BaseForm.__init__方法,把UnboundField对象转换成StringField对象,并赋值到form对象的_fields:{}字典中;
form = {
_fields: {
name: StringField对象(),
pwd: PasswordField对象(),
}
循环form对象 中的_fields字段(字典),分别赋值到form对象,这样就可以通过form.name/form.pwd直接获取到Field对象了
,无需form._fields['name'] / form._fields['name']
代码:
for name, field in iteritems(self._fields):
setattr(self, name, field)
form对象封装数据就变成以下内容喽

form = {
_fields: {
name: StringField对象(),
pwd: PasswordField对象(),
}
name: StringField对象(widget=widgets.TextInput()),
pwd: PasswordField对象(widget=widgets.PasswordInput())
}

3. 当form对象生成之后 print(form.name) = 执行StringField对象的__str__方法;
StringField类中没有__str__方法,所以去执行基类Field的,Field.__str__方法返回了: self() = StringFieldObj.__call__()
StringField没有__call__所以执行其基类Field.__call__方法,调用了self.meta.render_field(self, kwargs)
def __call__(self, **kwargs): # self=StringField对象
return self.meta.render_field(self, kwargs) #把StringField对象传传入meta.render_field方法
下面来看self.meta.render_field(self, kwargs)做了什么?

def render_field(self, field, render_kw):
other_kw = getattr(field, 'render_kw', None)
if other_kw is not None:
render_kw = dict(other_kw, **render_kw)
# StringField对象.widget(field, **render_kw)
#插件.__call__()
'''
#field =StringField对象
StringField对象.widget对象()=调用widget对象的.__call__方法
'''
return field.widget(field, **render_kw)

来看widget对象=TextInput()的__call__方法,最终打印了obj.name的结果

def __call__(self, field, **kwargs):
kwargs.setdefault('id', field.id)
kwargs.setdefault('type', self.input_type)
if 'value' not in kwargs:
kwargs['value'] = field._value()
if 'required' not in kwargs and 'required' in getattr(field, 'flags', []):
kwargs['required'] = True
return HTMLString('<input %s>' % self.html_params(name=field.name, **kwargs))


"""
0. Form.__iter__: 返回所有字段对象
1. StringField对象.__str__
2. StringField对象.__call__
3. meta.render_field(StringField对象,)
4. StringField对象.widget(field, **render_kw)
5. 插件.__call__()
"""

4.执行for iteam in form对象的执行流程
执行form对象基类BaseForm的__inter__方法,变量self._fields字典中的内容

def __iter__(self):
"""Iterate form fields in creation order."""
return iter(itervalues(self._fields))
_fields: {
name: StringField对象(),
pwd: PasswordField对象(),
}

用户输入数据的校验验证流程form = LoginForm(formdata=request.form)

# 请求发过来的值
form = LoginForm(formdata=request.form) # 值.getlist('name') # 实例:编辑
# # 从数据库对象
# form = LoginForm(obj='值') # 值.name/值.pwd
#
# # 字典 {}
# form = LoginForm(data=request.form) # 值['name'] # 1. 循环所有的字段
# 2. 获取每个字段的钩子函数
# 3. 为每个字段执行他的验证流程 字段.validate(钩子函数+内置验证规则)

六、session功能
1. Flask自带的session功能
2.第三方session组件(Session)
安装 pip install flask-session
不仅可以把session存放到redis还可放到文件、内存、memcache...
3.自定义session组件
七、蓝图
使用Flask自带Blueprintmuk模块,帮助我们做代码目录结构的归类

八、message (闪现)
message是一个基于Session实现的用于保存数据的集合,其特点是:一次性。
特点:和labada匿名函数一样不长期占用内存
九、中间件
flask也有中间件功能和Django类似,不同的是使用的是使用3个装饰器来实现的;
1.@app.before_first_request :请求第1次到来执行1次,之后都不执行;
2.@app.before_request:请求到达视图之前执行;(改函数不能有返回值,否则直接在当前返回)
3.@app.after_request:请求 经过视图之后执行;(最下面的先执行)
十、Flask相关组件
2、flask-script组件
flask-script组件:用于通过脚本的形式,启动 flask;(实现类似Django的python manager.py runserver 0.0.0.0:8001)
pip install flask-script #安装
python run.py runserver -h 0.0.0.0 -p 8001
* Running on http://0.0.0.0:8001/ (Press CTRL+C to quit)
3.flask-migrate组件
在线修改、迁移数据库(Django的 migrate 。
pip install flask-migrate #安装
3.1.初始化数据库:python run.py db init
3.2.迁移数据: python run.py db migrate
3.3.生成表: python run.py db upgrade
ps:修改表结构 first 直接注释静态字段代码,second 执行 python run.py db upgrade.

D:\Flask练习\sansa>python run.py db init
Creating directory D:\Flask练习\sansa\migrations ... done
Creating directory D:\Flask练习\sansa\migrations\versions ... done
Generating D:\Flask练习\sansa\migrations\alembic.ini ... done
Generating D:\Flask练习\sansa\migrations\env.py ... done
Generating D:\Flask练习\sansa\migrations\README ... done
Generating D:\Flask练习\sansa\migrations\script.py.mako ... done
Please edit configuration/connection/logging settings in 'D:\\Flask练习\\sansa\\migrations\\alembic.ini' before proceeding. D:\Flask练习\sansa>python run.py db migrate
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'users666'
Generating D:\Flask练习\sansa\migrations\versions\a7f412a8146f_.py ... done D:\Flask练习\sansa>python run.py db upgrade
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> a7f412a8146f, empty message D:\Flask练习\sansa>

flask框架詳解的更多相关文章
- python flask框架详解
Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务.本文参考自Flask官方文档, 英文不好的同学也可以参考中文文档 1.安装flask pi ...
- Flask框架【七】—session组件详解
一.flask session简介 flask中session组件可分为内置的session组件还有第三方flask-session组件,内置的session组件缺点: 功能单一 session是保存 ...
- SpringMVC常用注解實例詳解3:@ResponseBody
我的開發環境框架: springmvc+spring+freemarker開發工具: springsource-tool-suite-2.9.0JDK版本: 1.6.0_29tomcat ...
- SpringMVC常用注解實例詳解2:@ModelAttribute
我的開發環境框架: springmvc+spring+freemarker開發工具: springsource-tool-suite-2.9.0JDK版本: 1.6.0_29tomcat ...
- flask框架+pygal+sqlit3搭建图形化业务数据分析平台
一. 前言 先说下主要的框架和主要的图形库的特点:(个人见解) Django:python开发的一个重量级的web框架,集成了MVC和ORM等技术,设计之初是为了使开发复杂的.数据库驱动的网站变得简单 ...
- Flask框架搭建一个日程表
目录 前言 项目介绍 技术栈 Flask Web开发流程 一.搭建环境 1.1: 创建虚拟环境 1.2: 安装依赖包 1.3: 创建依赖包列表文件 1.4: 测试hello word 二.应用程序开发 ...
- Flask 框架理解(一)
Flask 框架理解(一) web 服务器 , web 框架 以及 WSGI 这里说的 web 服务器特指纯粹的 python HTTP 服务器(比如 Gunicorn,而不是 Apache,Ngin ...
- Flask框架知识点整合
Flask 0.Flask简介 Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收ht ...
- flask框架-下
Local与偏函数 threasing.local 多个线程修改同一个数据,复制多份变量给每个线程用,为每个线程开辟一块空间进行数据存储. 不使用therading.local # 不用local f ...
随机推荐
- 【Spark 深入学习-08】说说Spark分区原理及优化方法
本节内容 ------------------ · Spark为什么要分区 · Spark分区原则及方法 · Spark分区案例 · 参考资料 ------------------ 一.Spark为什 ...
- 【emWin】例程十七:窗口对象——Button
介绍: 按钮小工具通常用作触摸屏的主要用户界面元素,本例程介绍按钮小工具的创建及使用方法. 触摸校准(上电可选择是否进入校准界面) 自绘按钮(通过回调函数来自行绘制各种形状的按钮) 设置按钮字体 设置 ...
- 【WPF】图片按钮的单击与双击事件
需求:ListBox中的Item是按钮图片,要求单击和双击时触发不同的事件. XAML中需要引入System.Windows.Interactivity.dll xmlns:i="clr-n ...
- 3D 特征点概述(1)
很久没有更新相关内容了,很多朋友过来私信我,但由于时间问题,不能一一为大家解答,本人也不是无所不知的大神,还请各位谅解. 本文主要总结PCL中3D特征点的相关内容,该部分内容在PCL库中都是已经集成的 ...
- Java知多少(85)文本框和文本区
在图形界面中,文本框和文本区是用于信息输入输出的组件. 文本框 文本框(JTextField)是界面中用于输入和输出一行文本的框.JTextField类用来建立文本框.与文本框相关的接口是Action ...
- eBGP&iBGP 总结
3.4 BGP 原文地址:http://mp.weixin.qq.com/s?src=3×tamp=1500043305&ver=1&signature=XwiIVV ...
- python中的生成器函数是如何工作的?
以下内容基于python3.4 1. python中的普通函数是怎么运行的? 当一个python函数在执行时,它会在相应的python栈帧上运行,栈帧表示程序运行时函数调用栈中的某一帧.想要获得某个函 ...
- Hbase学习笔记——基本CRUD操作
进入Hbase的安装目录,启动Hbase bin/start-hbase.sh 打开shell命令行模式 bin/hbase shell 关闭Hbase bin/stop-hbase.sh 一个cel ...
- 和我一起学Effective Java之泛型
泛型 不要在新代码中使用原始类型 泛型(generic):声明中具有一个或多个类型参数 原始类型(raw type):不带任何实际类型参数的泛型名称 格式: 类或接口的名称 < 对应于泛型形式类 ...
- SQLSVR 之 EXISTS
来个实例看看 CREATE TABLE #temp( id BIGINT, name VARCHAR(max), age INT ) CREATE TABLE #tempmain( id BIGINT ...