缺省情况下, Flask 不包含数据库抽象层、表单验证或者其他已有的库可以处理 的东西。然而, Flask 通过扩展为应用添加这些功能。 (自己创建文件或者目录)
Flask 会一直提供一个 非常简约而优秀的胶合层,就像 Python 语言一样。你可以自由地使用 SQLAlchemy 执行高级模式,或者使用其他数据库工具,亦可引入非关系数据模型, 甚至还可以利用用于 Python 网络接口 WSGI 的非框架工具。
模板和静态文件存放在应用的 Python 源代码树的子目录中,名称分别为 templates 和 static 。
Werkzeug ( WSGI )和 Jinja (模板)是两个被广泛使用的工具,而 Flask 起源
就是用于展示如何基于这两个工具创建你自己的框架。
Flask 的主要代码都在 Werkzeug 和 Jinja2 这两个库内。这两个库起了主要作用。 Flask 只是把它们粘合 在一起而已。
$ pip install Flask
自主创建文件、目录
1.webapp包目录,存放flask代码,包内有__init__.py文件
2.templates目录,存放模板文件
3.static目录,存放js、css等静态文件。其下建立js目录,放入jquery、echarts的js文件
4.app.py,入口文件 基本组成
#建议写在webapp包目录
#flask的继承
from flask import Flask
#创建应用
app = Flask(__name__)
app = Flask('web')
flask增加网页路由规则,采用flask继承并生成对象 (app) 做装饰器
Flask使用了Jinja2模板。
对于应用app来说其模板是,根目录下的templates,其下新建index.html
html 中支持 jianjia2语法
jianjia2语法可以查看:
https://www.jianshu.com/p/83f5c3fd264c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
#add_url_rule(rule, endpoint=None, view_func=None, provide_automatic_options=None, **options)
from flask import render_template , Flask
app = Flask('web')
#路由和视图函数
@app.route('/')
def index():
userlist =list(range(100,110))
return render_template('index.html',userlist=userlist)
应用:创建出来提供WEB服务的实例,也是wsgi的入口
视图函数:执行内部代码输出响应的内容index
路由:通过route装饰器创建path到视图函数的映射关系
更多类对象API方法查看:
https://dormousehole.readthedocs.io/en/latest/api.html#flask.Flask
# app.py
from webapp import app
if __name__ == '__main__':
app.run('0.0.0.0',80,True)
蓝图是一种组织 一组相关视图函数和其他代码的方法。使用蓝图注册它们。 然后,当蓝图在工厂函数中可用时,将向应用程序注册蓝图。
Flask 有两个蓝图,一个用于身份验证功能,另一个用于博客文章功能。 每个蓝图的代码将放在一个单独的模块中。
由于博客需要了解身份验证,因此您将首先编写身份验证。
Flask中,基本上都是route装饰器和视图函数的映射,如果函数很多,代码组织结构会非常乱。
蓝图Blueprint,就是Flask中模块化的技术。
# webapp/books.py
# 创建蓝图
from flask import Blueprint , jsonify # 自带dump
#相当于这个一个应用
#可以单独指定模板路径,如果是相对路径,则表示从项目根目录开始
books = Blueprint('book',__name__,template_folder='ttt',url_prefix='/aaa')
#第一个参数 为注册的蓝图 key ('book')
#与应用程序对象一样,蓝图需要知道它的定义位置,因此将 __name__ 作为第二个参数传递。 url_prefix 将被添加到与蓝图关联的所有 URL。
@books.route('/')
def all():
books = [
(0,'管子',90.0),
(1,'山海经',90.0),
(2,'墨子',90)
]
return jsonify(books)
#app.register_blueprint(books) #默认蓝图的所有url都挂到站点根路径上
app.register_blueprint(books,url_prefix='/bbb')#url_prefix='/bbb'
蓝图更多方法可在flask官网,搜索“Blueprint Objects”查看
https://flask.palletsprojects.com/en/2.0.x/api/#blueprint-objects
falsk 实战
gunicorn部署Flask服务
作为一个Python选手,工作中需要的一些服务接口一般会用Flask来开发。
Flask非常容易上手,它自带的app.run(host=“0.0.0.0”,
port=7001)用来调试非常方便,但是用于生产环境无论是处理高并发还是鲁棒性都有所欠缺,一般会配合WGSI容器来进行[生产环境的部署]经过调研和尝试
gunicorn可以结合gevent来进行部署,因此在高并发场景下也可适用,于是决定采用gunicorn进行部署。
gunicorn和supervisor会有一定的冲突,即使gunicorn中没有设置为后台启动,supervisor也只会管理gunicorn的master进程;
supervisor的重启服务对于无响应的Flask进程来说并不生效,不能很好地解决我的服务由于某些原因无法正常响应但又找不到方法解决的问题,因此暂时决定不用supervisor。
环境安装
首先pip安装gunicorn。 pip install gunicorn --user
由于是部署在公司云主机上,通常不会给root权限。之前都是提工单给SA sudo装的,后来发现更安全也更方便的方法是pip install
xxx --user,美中不足是安装完以后需要手动添加PATH export
PATH=/home/username/.local/bin:$PATH 方便起见可以加到~/.bash_profile中如果是root用户安装可以不用加 --user
使用本人的程序需要用到redis,所以命令启动 flask 需要用到redis,所以需要先启动redis
> cat /etc/rc.local
> cd /root/redis/redis-xx.xx.x/src/ &&
> ./redis-server & cd /root/flask && gunicorn start:app -c gunicorn.conf &
> ulimit -n 2048
这种方式启动flask ,相关的配置在gunicorn.conf中配置了
如果是简单启动,可以直接使用命令
gunicorn -w 4 -b 127.0.0.1:4000 start:app
启动一个flask应用。其中
-w 4 是指定工作进程数为4
-b 是绑定地址和端口
start 是flask的启动python文件。
app 是start.py 文件中定义的flask名称 例如:app = Flask(name)
通过gunicorn -h可以看到gunicorn有非常多的配置项,因此通常会写成一个config.py文件来进行配置。
例如:
gunicorn.conf
workers = 1
#只启动一个进程。
bind = '0.0.0.0:5000'
#绑定的本地的端口
daemon = False
#守护进程是False。如果是True的话,会导致start.py中的shell命令无法执行,True的意思为后台运行。运行的时候加 & 效果一样。还可以支持一些shell命令。
timeout = 600
#设置超时时间
logging = {
'xxxx'
'xxxx'
'xxxx'
}
#日志的参数 handlers, formatters 根据自己的需求进行填写,与python类似。
我使用的是nginx将本地的0.0.0.0:4000的地址映射出去,实现nginx + wsgi的功能。nginx作为帮助响应的一个角色。
为了安全起见:可以独立开一个目录
nginx.conf 中
http{} 中增加一个地址
include /etc/nginx/sites-enabled/*
在目录下编辑一个default文件就可
增加一个server{} , 或者在存在server里写也可以
listen 8999;
server_name flask;
allow all;
location / {
proxy_pass http://127.0.0.1:4000/xxxx/api;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}