flask文档:
- 中文文档(http://docs.jinkan.org/docs/flask/)
- 英文文档(http://flask.pocoo.org/docs/1.0/)
- 扩展列表 http://flask.pocoo.org/extensions/
写在前面:
必须要明白的三个问题:
- 我们为什么要学框架?
- 为什么要学不同的框架?
- 学习框架都应该学什么?
1. 我们为什么要学框架?
框架只是一种工具,使用工具的目的就是为了解决问题(需求)。
2. 为什么要学不同的框架?
根据需要解决的问题(需求)的不同我们需要使用不同的工具(框架)
3. 框架都应该学些什么?
每一种框架提供了很多的方法和API,要全记住是相当困难的。最好的办法是——遇到不会的就去查文档。所以在工具的学习上,我的办法是——了解每种工具的使用场景(能处理的需求),以及理解问题的内在本质,探究解决问题的思路,可能没有最好的工具,只有更合适的工具。
flask&django
flask
轻量级框架,只提供web开发的核心功能。目录结构自己玩,想怎么搭就怎么搭。
django
重量级框架,除web开发核心功能外,还提供manage.py 管理项目功能、admin后台管理站点、用户认证、数据库操作、文件存储系统、缓存机制等。
关于框架的选择:没有最好的,只有更合适的。
轻:只提供核心功能,方便、灵活、高度定制化。(技术选型可能会不断的调整,需要框架对自己的约束越小越好。)
重:功能强大,需求确定能用django很好的完成需求,就用django。(快速实现业务,不考虑技术选型,越简单直接越好)
工程搭建
- 创建虚拟环境
mkvirtualenv flask -p python3
创建一个虚拟环境叫:flask, -p指定python版本为python3。
之前在django学习中指定了django版本为:1.1.11,是因为django2的版本不是为稳定的。(2和1的语法有些许不一样)flask直接使用最新的(1.0.2)。
- 安装flsak
# 检查下当前虚拟环境版本
python --version
pip install flask
截图如下:
安装完成后:pip list 查看下当前安装列表
文件结构
单文件结构项目搭建
from flask import Flask
app = Flask(__name__)
# 定义视图
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
区别:
- django 视图函数第一个参数必须接收request对象。
- django返回一个对象时,要么使用render(),要么进行封装。
- django默认端口:8000,flask默认端口:5000
- 运行:python 模块
总结:
- 先创建app
- 通过app创建视图函数
- 通过python run 一个模块。
- ctrl+d退出
参数说明
- Flask对象的初始化参数
- 应用程序配置参数
- app.run()运行参数
1. Flask对象初始化参数
app = Flask(__name__)
具体参数可查看底层代码,常用的有四个:
- import_name: 用于寻找工程目录。
1.__name__ : " 魔法变量",当前模块名。传给Flask对象的值,如果当前是工程目录下的启动模块则传递的内容为“__main__”。
此时便会启动该工程。
- flask自动把当前模块所在的模块当作工程目录。
- flask找到了对应的主的工程目录后会自动去寻找templates、static等。
django 则需要在settings里面设置。
工程目录: 启动模块所在的目录
- static_url_path: 默认为:/+static_folder
- static_folder: 默认为:staatic
- template_folder: 默认为:templates
2. 应用程序配置参数
flask对象初始化参数设置的是flask本身的属性。
应用程序配置参数设置的是web应用工程的相关信息。
作用:集中管理项目的所有配置信息
使用方式
django将所有的配置信息都放到了settings.py文件中。
Flask将配置信息保存到了 app.config 属性中,该属性可以按照字典类型进行操作。
读取
- app.config.get(name)
- app.config[name]
设置
1. 从配置对象中加载
app.config.from_object(自定义的配置对象)
原理:自己定义一个类,在类中定义好应用程序的配置信息。
通过app.config中的from_object()方法加载
class DefaultConfig(object):
"默认设置"
SECRET_KEY = "HUAHGAJGHnhugJI"
app = Flask(__name__)
# 从配置对象中导入
app.config.from_object(DefaultConfig)
@app.route("/")
def index():
return "hello flask"
note: 所有的配置项都需要大写。
优点:
- 继承、复用。
缺点:
- 敏感信息暴露在代码中了(比如私钥)
应用场景:
- 设置默认参数
2. 从配置文件中加载
app.config.from_pyfile(配置文件名)
原理:自定义配置文件
利用“from_pyfile()”方法加载配置文件。
# 新建一个配置文件settings.py
SECRET_KEY = '..................................'
# 在项目文件中
app = Flask(__name__)
app.config.from_pyfile('settings.py')
@app.route('/')
def index():
return "hello python"
优点:
独立文件>保护敏感数据。(可以将文件从代码中剥离出去,指定绝对路径)
应用场景: 在项目中使用固定的配置文件。
缺点:
文件路已经固定,不灵活。(Windows和liunx文件路径表示方式不一样,此时需要修改代码。)
3. 从环境变量中加载
环境变量: 有操作系统代为保存的变量值。
设置&读取
export 变量名 = 变量值(这个值是一个配置文件地址)
echo $变量名 # 获取:$变量名 echo:将获取的结果打印出来。
原理:通过环境变量值找到配置文件,再读取配置文件信息。
app.config.from_envvar(环境变量名)
- 环境变量值为配置文件的绝对路径(以工程目录开始)
- 先在终端执行
export PROJECT_SETTING='~/setting.py'
- 运行如下代码
app = Flask(__name__)
app.config.from_envvar('PROJECT_SETTING',silent=True)
@app.route("/")
def index():
return "hello python"
silent: 默认为False,当查找参数不存在时,系统会报错。silent=True时,查找参数不存在时,程序也不会报错。
在pycharm中运行:
silent= True 也会报错!(在终端设置的变量虽然保存到操作系统,但是只有终端才能拿到,pycharm是另一个程序,每个程序运行的环境都是不一样的。)
解决: 在模块文件的"编辑"下,找到"envariment vari…"添加环境变量名字和值。
优点:
独立文件,保护敏感数据,文件路径不固定,很灵活。(固定的只是一个名字,在不同环境下代码基本不用变)
缺点:
不方便,记得在在终端和pycharm中设置环境变量。
实际开发中的方案
- 以从对象中加载的方式,为参数设置默认值。
- 以从环境变量加载的方式为,敏感信息设置真实值。
工厂函数
将 实列化Flask对象、从对象中加载配置信息、从环境中加载配置信息封装成一个函数——工厂函数。
def create_flask_app(config):
app = Flask(__name__)
app.config.from_object(配置对象名)
app.config.fom_envvar('环境变量名',silent=True)
return app
class DefaultConfig(object):
配置信息名(大写)= 值
class DevelopConfig(DefaultConfig):
DEBUG = True # 测试环境下使用
app = create_flask_app(DevelopConfig) # 此app已经h含有配置参数。
# 定义视图函数
@app.route('路由规则')
def index():
return "index.html"
3. app.run参数
app.run() 运行调试服务器。运行服务器,需要IP和端口号,所以可指定运行主机IP地址,端口,是否开启调试模式
app.run(host="0.0.0.0",port=5000,debug = True)
debug调试模式:
- 程序修改代码后可以自动重启服务器
- 在服务器出现相关错误的时候可以直接将错误信息返回到前端进行展示
开启服务器启动方式
在1.0版本之后,Flask开启服务的方式由代码app.run() 替换为终端命令 :
flask run:
代码中只需要出现flask应用和flask视图 if 判断开始的app.run()不需要。
若有多个文件
- export FLASK_APP=实列名
export FLASK_APP=app # app为实列名,注意”=“两边没有空格。
-
环境变量FLASK_APP指明flask的启动实例
-
flask run -h 0.0.0.0 -p 8000 绑定地址 端口
-
flask run --help 获取帮助
-
生产模式与开发模式的控制:
A. 通过FLASK_ENV指明环境变量
- export FLASK_ENV = production
- export FLASK_ENV = development
flask run:默认运行在生产环境(production),debug = off
export FlASK_ENV = development
flask run: 开发环境中,debug = on
优点:新式生产模式与开发模式控制:不需要修改代码,直接通过终端运行命令来控制开发环境。
路由与蓝图
在flask中我们发现路由是跟着视图函数走的。
Q?:如何查看所有的路由信息?
查询路由信息
1. 终端命令:
flask routes
结果:
字段:
- Endpoint:
- Methods:
- Rule:
2. 在程序中通过代码的方式获取:
应用中的url_map属性保存着整个Flask应用的路由映射信息。
app.url_map
eg:
(untitled) python@ubuntu:~/untitled$ export FLASK_APP=app
(untitled) python@ubuntu:~/untitled$ flask run
* Serving Flask app "app"
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
Map([<Rule '/' (HEAD, OPTIONS, GET) -> hello_world>,
<Rule '/s/<filename>' (HEAD, OPTIONS, GET) -> static>])
<class 'werkzeug.routing.Map'>
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
需求:需要遍历url_map 取出特定信息 在一个特定的接口返回。
for rule in app.url_map.iter_rules():
print('name={},path={}'.format(rule.endpoint,rule.rule))
format函数参考连接:https://blog.youkuaiyun.com/xyx_x/article/details/90202813
import json
@app.route("/")
def route_map():
"""
主视图,返回所有视图的url
"""
rules_iterator = app.url_map.iter_rules()
return json.dumps({rule.endpoint:rule.rule for rule in rules_iterator})
蓝图(Blueprint)
需求: 在Flask应用的项目中,业务视图过多时,划分业务单元单独维护,将每个单元用到的视图、静态文件、模板独立分开。
Flask中通过Flask对象创建的一个app相当于django中的工程。在dajngo中一个模块一个文件很方便复用。
在Flask中每一个应用用“蓝图”表示。
作用:方便复用、扩展、移植
特点:
- 一个应用可以有多个蓝图
- 可以给每个蓝图添加URL前缀,方便区分不同蓝图所代表的的模块。比如:"/user"、“/goods”
- Blueprint可以单独具有自己的模板、静态文件、方法等。并不是必须要实现的应用的视图和函数。
- 应用初始化(创建一个app)时,必须要注册到某一个应用中。
使用:
单文件蓝图
可以将创建的蓝图对象与定义的视图放到一个文件夹中。
1. 创建一个蓝图对象
user_bp = Blueprint('user',__name__)
‘user’:为蓝图名,注册时会使用。
‘name’:表示以当前目录作为蓝图查找资源得目录。
2. 操作蓝图(注册路由、指定静态文件夹、注册模板过滤器…)创建视图时,使用由蓝图对象里的路由装饰器进行设置
@user_bp.route("profile")
def get_profile():
return "user profile"
3. 注册蓝图对象+url前缀
app.register_blueprint(user_bp,url_prefix='/user')
此时访问get_profile文件路由:127.0.0.1:5000/user/profile
目录蓝图
- 创建一个python包
- 蓝图应该在__init__.py文件中创建
from flask import Bolueprint
goods_bp = Blueprint('goods',__name__)
- 蓝图视图可以新建一个文件夹(如:views.py)
from . import goods_bp
@goods_bp.route('/')
def get_goods():
return "...."
- 在app里注册该蓝图:
app.register_blueprint(‘蓝图名’,url_prefix='')
一顿操作猛如虎,结果发现找不到视图函数!!!——这程序文件运行时只运行了蓝图目录的__init__.py文件。
so 我们应该在__init__.py文件的最后导入蓝图目录中其它模块。
按照PEP8规范,在程序的最开头导包,会因为循环导包---->导入失败。
对比两个模块:
# 1. __init__.py文件
from flask import Blueprint
from . import views
goods_bp = Blueprint('goods',__name__)
# views.py
from . import goods_bp
@ goods_bp.route('/goods')
def get_goods():
return '调用了get_goods这个视图'
当主程序运行到from 蓝图目录 import 蓝图
执行__init__.py文件 ,当需要使用views模块时,并没有goods_bp对象,所以在views中导入这个对象就会出错。
扩展用法
- url_prefix: 注册蓝图时指定蓝图的URL前缀。
app.register_blueprint(user_bp,url_prefix="/user")
- static_folder: 指定内部静态文件目录
为蓝图指定静态目录路由(应用对象床架时会有默认静态文件路由,而蓝图对象没有)当在蓝图内部使用静态文件必须显示指明。
admin = Blueprint("admiin",__name__,static_folder="static_sdmin")
app.register_blueprint(admin,url_prifix="/admin")
- **template_folder:**指定内部模板目录
admin = Blueprint('admin',__name__,template_folder="my_temlates")
小结:
-
Flask轻量级web框架,只解决了web开发的核心内容——如何处理视图,编写业务逻辑。如何处理请求,构造响应。提供了一个jinja2模板。
-
Flask本身依赖了一个开源的Werkzeud的库
-
需要知道flask与django的对比以及选择性的问题。
-
Flask程序的书写:
- 创建flask对象作为全局应用对象。
- 编写视图
- flask参数
- 工程配置参数(3种)
- 工厂函数
- 两种调试服务器运行方式
-
查询路由(flask routes /app.url_map)
-
蓝图