一、Flask简介
Django 重型框架
Flask 轻量级框架
Flask是一个基于Python实现的Web开发‘微’框架 'MicroFramework'
官方文档: http://flask.pocoo.org/docs/0.12/
中文文档: http://docs.jinkan.org/docs/flask/
Flask是一个基于MVC设计模式的Web后端框架
MVC:
M Model 数据模型
V View 界面
C Controller 控制器
MTV
M: Models 模型(数据)
T: Templates 模板(界面)
V: Views 视图(控制器)
Flask依赖三个库
Jinja2 模板引擎 {% %} 模板:静态html+模板语言{% %}
Werkzeug WSGI工具集
流行的Flask
Flask流行的主要原因:
1. 有非常齐全的官方文档,上手非常方便
2. 有非常好的扩展机制和第三方扩展环境,工作中常见的软件都会有对应的扩展。自己动手实现扩展也很容易
3. 社区活跃度非常高
4. 微型框架的形式给了开发者更大的选择空间
二、Flask项目创建和基本使用
-
创建项目
1.创建虚拟环境
mkvirtualenv flaskenv2.在虚拟环境中安装flask
pip install flask3.创建flask项目
3.1直接打开PyCharm,新建一个Flask项目(一般按此操作),在项目下的app.py文件中会存在以下代码:
from flask import Flaskapp = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() 3.2 或者手动新建一个,写入以上代码
4.run()启动时可以添加参数:
app.run(debug=True,host=‘0.0.0.0’,port=5001)
debug 是否开启调试模式,开启后修改过python代码会自动重启
port 启动指定服务器的端口号,默认是5000
host 主机,默认是127.0.0.1,指定为0.0.0.0代表本机所有ip
2.Flask插件
2.1. Flask插件优缺点
Flask是一个微型框架,除了Flask自带的核心功能外,其他大部分功能都需要利用Flask提供的插件。
优点:灵活,可以根据项目功能需求灵活使用需要的插件
缺点:核心功能较少,针对稍大的项目每次都需要自己集成插件
2.2. flask-script 插件
flask-script 扩展提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Python shell,设置数据库的脚本及其他运行在web应用之外的命令行任务;使得脚本和系统分开;
1.安装
pip install flask-script
2.初始化
manager = Manager(app)
3.调用
在run的地方修改,修改manager.run():
if __name__ == '__main__':
manager.run()
4.启动服务器
1)可以在命令行中使用: python manage.py runserver
2)还可以接收参数: python manage.py runserver -p 8000 -h 0 -d -r
p 端口 port
h 主机 host
d 调试模式 debug
r 重启(重新加载) reload(restart)
- 项目拆分
代码全都写在manage.py一个文件中是不现实的, 我们可以对项目进行简单的拆分
一般需要对新建项目进行结构优化后执行:
1)将app.py文件重命名为manage.py;
2)新建一个名为App的包(即包含__init__.py文件的目录);
3)将static、templates文件夹移入APP目录下;
4)在App目录下新建models.py、views.py文件
5)init中代码如下:
from flask import Flask
# 创建app
def create_app():
app = Flask(__name__)
return app
6)manage.py中代码如下:
from flask_script import Manager
from App import create_app
# 创建app
app = create_app()
# 创建manager对象
manager = Manager(app)
if __name__ == '__main__':
manager.run()
-
蓝图blueprint
1)宏伟蓝图(宏观规划)
2)蓝图也是一种规划,主要用来规划urls(路由route)
3)蓝图基本使用
在views.py中初始化蓝图
blue = Blueprint(‘user’, name)在init文件中调用蓝图进行路由注册
app.register_blueprint(blueprint=blue)#扩展理解
1.Blueprint概念
简单来说,Blueprint 是一个存储操作方法的容器,这些操作在这个Blueprint 被注册到一个应用之后就可以被调用,Flask 可以通过Blueprint来组织URL以及处理请求。
2.蓝图使用
蓝图/Blueprint对象用起来和一个应用/Flask对象差不多,最大的区别在于一个 蓝图对象没有办法独立运行,必须将它注册到一个应用对象上才能生效使用蓝图可以分为三个步骤:
1)创建一个蓝图对象
在views.py中初始化蓝图
blue = Blueprint(‘user’, name)
2)在这个蓝图对象上进行操作,如注册路由,指定静态文件夹,注册模版过滤器等,形式是装饰器注册路由
@admin.route(’/’)
def admin_home():
return ‘admin_home’
3)在app应用对象中注册蓝图对象,即在init文件的cerate_app函数下添加:
app.register_blueprint(blueprint=blue)
当create_app被调用时,则可以对蓝图中定义的视图函数进行访问
3.运行机制
1)蓝图是保存了一组将来可以在应用对象上执行的操作,注册路由就是一种操作
2)当在应用对象上调用 route 装饰器注册路由时,这个操作将修改对象的url_map路由表
3)然而,蓝图对象根本没有路由表,当我们在蓝图对象上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一个项
4)当执行应用对象的 register_blueprint() 方法时,应用对象将从蓝图对象的 defered_functions 列表中取出每一项,并以自身作为参数执行该匿名函数,即调用应用对象的 add_url_rule() 方法,这将真正的修改应用对象的路由表 -
route路由
路由:
将从客户端发送过来的请求分发到指定函数上路由通过装饰器对应视图函数,并且可以接收参数,所以我们只需要在视图函数上使用装饰器即可
1、语法
@app.route(‘/rule/’)
def hello():
return ‘Hello World!’2、路由的参数
1)写法:converter:variable_name
例:
@blue.route(’/getid/int:id/’)
def get_id(id):
print(id,type(id))
return str(id)
2)类型
string 默认类型,接收任何没有斜线(’/’)的文件
@blue.route(’/getname//’)
def get_name(name):#关键字参数,相当于get_name(name=name)
print(name,type(name))#str
return name
# http://127.0.0.1:5004/getname/haha/
#hahaint 接收整型
@blue.route(’/getid/int:id/’)
def get_id(id):
print(id,type(id))
return str(id)
# http://127.0.0.1:5004/getid/100/
#100float 接收浮点型
@blue.route(’/getmoney/float:money/’)
def get_money(money):#不可传整数,必须带小数点
print(money,type(money))
return str(money)
# http://127.0.0.1:5004/getmoney/100/
#404错误
# http://127.0.0.1:5004/getmoney/10.0/
#10.0path 接收路径,可接收斜线(’/’)
@blue.route(’/getpath/path:path/’)
def get_path(path):
print(id,type(path))
return path
#http://127.0.0.1:5000/getpath/l/i/s/i/
#返回:l/i/s/iuuid 只接受uuid字符串,唯一码,一种生成规则
@blue.route(’/getuuid/uuid:uid/’)
def get_uuid(uid):
print(uid,type(uid))
return str(uid)
# http://127.0.0.1:5004/getuuid/7334f626-3f7e-4982-b646-f9be5c10fc23/
#7334f626-3f7e-4982-b646-f9be5c10fc23any 可以同时指定多种路径,进行限定
@blue.route(’/getfruit/<any(apple,orange,banana):fruit>/’,methods=[‘GET’,‘POST’])
def get_fruit(fruit):
print(fruit,type(fruit))
return str(fruit)#apple <class ‘str’>
#apple <class ‘str’>
#http://127.0.0.1:5004/getfruit/apple/
#apple -
Request
服务器在接收到客户端的请求后,会自动创建Request对象
由Flask框架创建,Request对象不可修改
request是一个全局变量,在使用时导入即可属性
url 完整请求地址
base_url 去掉GET参数的URL
host_url 只有主机和端口号的URL
path 路由中的路径
method 请求方法
remote_addr 请求的客户端地址
args GET请求参数
form POST请求参数
files 文件上传
headers 请求头
cookies 请求中的cookie
remote_addr 客户端ipImmutableMultiDict: 类似字典的数据结构, 与字典的区别,可以存在相同的键
args和form都是ImmutableMultiDict的对象
ImmutableMultiDict中数据获取方式
dict[‘uname’] 或 dict.get(‘uname’)
获取指定key对应的所有值
dict.getlist(‘uname’)- args
- get请求参数的包装,args是一个ImmutableMultiDict对象,类字典结构对象
- 数据存储也是key-value
- 外层是列表,列表中的元素是元组,元组中左边是key,右边是value
- form
- 存储结构个args一致
- 默认是接收post参数
- 还可以接收 PUT,PATCH参数
#Request:包含客户端传过来的数据
#地址:http://127.0.0.1:5000/getrequest/name=haha&like=1&like=2&like=3
@blue.route((’/getrequest/’))
def get_request():print(request,type(request)) # <Request 'http://127.0.0.1:5000/getrequest/' [GET]> # <class 'werkzeug.local.LocalProxy'> print(request.url)#完整路径 http://127.0.0.1:5000/getrequest/?name=haha&like=1&like=2&like=3 print(request.base_url)#不含GET参数路径 http://127.0.0.1:5000/getrequest/ print(request.path)#路径 /getrequest/ print(request.host_url)#只有主机和端口号的URL http://127.0.0.1:5000/ print(request.args) #ImmutableMultiDict([('name', 'haha'), ('like', '1'),('like', '2'), ('like', '3')]) #GET请求参数,类似Django中的QueryDict,可以存在相同的key,元组中的第一个参数为key,后一个参数为value print(request.files)#文件上传 print(request.form)#POST参数 print(request.args)#GET参数 print(request.cookies)#请求中的cookie {} print(request.remote_addr)#客户端ip 127.0.0.1 print(request.method)#请求方法 GET print(request.headers)#请求头 ''' Host: 127.0.0.1:5000 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: keep-alive Upgrade-Insecure-Requests: 1 Cache-Control: max-age=0 ''' print(request.user_agent)#客户端信息(可用于筛选爬虫) ''' Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0 127.0.0.1 - - [19/Aug/2019 15:08:01] "GET /getrequest/?name=haha&like=1&like=2 &like=3 HTTP/1.1" 200 - ''' return "request ok"
- args
-
Response
服务器返回给客户端的数据
由程序员创建,返回Response对象- 直接返回字符串, 可以返回文本内容,状态码
- render_template 渲染模板,将模板转换成字符串
- 通过make_response(data,code)
- data 返回的数据内容 - code 状态码
- 返回Response对象
举例
‘’’
index.html内容:
首页
{{ name }}
{{ age }}
''' @blue.route('/getresponse/') def get_response(): #1.直接返回字符串 return "response ok" #结果:response ok#2.render_template 渲染模板,将模板转换成字符串 #return render_template('index.html')#报错,一定要保证templates与当前文件在同一目录下 return render_template('index.html', name="zhangsan")#将static与template文件夹复制到App下 #结果:得到一个html字符串化后的结果 ''' ...... <body> <h2>首页</h2> <hr> <p>zhangsan</p> <p></p> </body> </html> ''' #3.传参方式 + 2中的操作 params = { "name":"zhangsan", "age":33 } return render_template('index.html', **params) #得到的也是与2中类似的结果 #4.在3的基础上,使用jsonify返回json序列化的结果 return jsonify(params) #结果{ "age": 33, "name": "zhangsan" } #5. 通过make_response(data,code) res = render_template('index.html', **params)#渲染模板,将模板转换成字符串 print(res,type(res))#res是一个HTML字符串,类型<class 'str'> #6.response = Response(res) print(response,type(response))#Response对象 # < Response246bytes[200OK] > # < class 'flask.wrappers.Response'>
重定向
redirect()#视图中,调用其他函数
url_for(‘函数名’,参数=value)#HTML中,调用其他函数举例
@blue.route(’/makeredirect/’)
def make_redirect():
# return redirect(‘http://www.qq.com’)#网址跳转到腾讯首页
#return redirect(’/getresponse/’)#跳转到上面内容的页面#url_for('蓝图名称.视图函数名称') return redirect(url_for('user.get_fruit',fruit="apple"))#结果apple # 相当于=>Django中redirect(reverse())
终止执行, 抛出异常
主动终止 abort(code)举例
@blue.route(’/abort/’)
def make_abort():
abort(403)
return “error”捕获异常
@app.errorhandler(404)
def hello(e):
return ‘LOL’