【Python】十分钟学会用Flask编写web后台
1. 前言
对于Web后台开发,Java企业级框架SpringBoot当之无愧的王者,无论从执行效率还是从扩展性上面来说都是实实在在的企业级选择。正因为其兼顾太多方面,体系复杂而庞大,十分不适合一些需要轻量化的场景。另外对于不熟悉Java的同学来说,去理解SpringBoot的整个体系是需要足够多的时间成本的。
在Python中,我十分推荐使用Flask来构建web后台应用。理由有如下几个:
- 学习曲线平滑,学习中的每一个步骤都足够简单,能够很快构建起对Flask的理解。
- 性能足够应付大多数场景,经过测试,单机运行
gunicorn(一个Python的Http服务器),Qps居然可以达到4000。 - 社区活跃,扩展库多,调用方便。涵盖数据库,缓存,验证等等,甚至有完整的后台管理库,只需要安装一个包即可。
- 无缝衔接Python,Flask没有要求固定的代码结构,没有要求配置文件,没有要求注入方式,一切都像一个普通的Python类一样使用。
- 天生支持热部署(借助python动态语言特性),体积占用小,内存占用小,部署方便。
另外,我通常是用FLask作为Web后台来使用,前端通常使用React来构建,所以jinja2等模版框架鲜有涉及。在前日益提倡后端分离的今天,jinja2等模版的市场会越来越小,但用来写一点快速的后台管理还是很方便的。
聊了那么多,下面我们开始FLask的旅程!
2. Flask helloworld
下面就是一个完整的Flask应用了,并完成了根目录的映射,默认端口是5000。
from flask import Flask
app = Flask(__name__)
# 组件在此处初始化
@app.route("/")
def home():
return "Hello World"
if __name__ == "__main__":
app.run(debug=True)
在浏览器或者postman中打开:
http://localhost:5000
可以看到
Hello World
我们来对代码进行一一解读
1. 初始化
from flask import Flask
app = Flask(__name__)
导入Flask包,构建Flask类,其中有疑问的很可能是为什么要传递__name__参数,这是因为Flask会根据__name__来区分所在包。官方文档中提到,当你只使用单模块时,Flask(__name__)肯定是正确的。如果Flask应用是一个包,那么建议此处硬编码为包名字。一般都是传递__name__。
2. 定义接口
@app.route("/")
def home():
return "Hello World"
熟悉Springboot的同学就知道,这就是赤裸裸的Controller的RequestMapping呀。@是python装饰器,如果不了解装饰器的同学可以看我另外一篇文章,浅谈Python装饰器。
你只需要知道此处将home函数映射到/这个目录即可,当通过Http访问/,则会执行home函数,并将返回值作为Response返回给Http的请求方。
3. 运行Flask
if __name__ == "__main__":
app.run(debug=True)
运行参数默认为:
host:localhost,如果需要外网访问需要显式指定host='0.0.0.0'port:5000debug:False,debug参数为我们提供了编写代码时候的热加载功能,可以及时看到修改代码产生的效果,建议开启。在部署正式环境的时候需要将其修改为False(实际上不用,因为gunicorn调用Flask根本不会走__main__这块)。
其他参数可以暂时不做学习。
现在就打开浏览器输入http://localhost:5000看看效果吧。
4. 使用gunicorn运行Flask
简单使用:
gunicorn的默认地址:端口是localhost:8000。
gunicorn -w 4 "app:app"
更多常用参数:
gunicorn \
-D \
--access-logfile ~/log/gunicorn-access.log \
--error-logfile ~/log/gunicorn-error.log \
--log-file ~/log/gunicorn.log \
--reload \
-w 8 --threads 24 \
--worker-connections 10000 \
"app:app" \
-b "0.0.0.0"
-D:后台运行--access-logfile ~/log/gunicorn-access.log:访问日志--error-logfile ~/log/gunicorn-error.log:错误日志--log-file ~/log/gunicorn.log:普通日志--reload:代码修改后自动重新加载,热加载-w 4 --threads 8:4进程,8线程--worker-connections 1000:最大连接数"app:app":入口类-b "0.0.0.0":绑定0.0.0.0
查看当前运行的gunicorn进程树:
pstree -ap|grep gunicorn
5. 数据库组件
相信根据上述的学习,已经可以构建一个基本的可以相应外部请求的FLask应用了。
接下我们要引入数据库组件:SQLAlchemy。
数据库我们暂时用sqlite来进行学习,实际使用只需要把对应的连接字符串修改为你所使用的数据库对应的即可,我会给出示例。不知道你有没有发现,Flask很容易就能使用不同的数据库,而不需要额外的编码。
SQLAlchemy
安装
pip install Flask-SQLAlchemy
引用方式:
from flask import Flask
# 引入Flask-SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
#######
# 可以使用如下方式配置Flask
sqlalchemy_config = {
# "SQLALCHEMY_DATABASE_URI": "sqlite:///db.sqlite"),
"SQLALCHEMY_DATABASE_URI": "mysql+pymysql://root:root@localhost:3306/test_db",
"FOREIGN_KEYS": None,
"SQLALCHEMY_TRACK_MODIFICATIONS": False,
# "SQLALCHEMY_ECHO": True
}
# 也可以使用如下形式
# app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
# app.config["SQLALCHEMY_ECHO"] = True
# 配置app.secret_key,Flask做加密用
app.secret_key = "test"
# 生成SQLAlchemy对象,后面对数据库的操作全都是用这里定义的db了。
db = SQLAlchemy(app)
#######
## DDL
### 定义表
```python
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
# 仅仅本表关联company表
company_id = Ext.db.Column(Ext.db.INTEGER, Ext.db.ForeignKey('company.id'))
company = Ext.db.relationship('Company', foreign_keys=company_id)
# 本表关联company表,company表也要建立访问本表的引用
company_id = Ext.db.Column(Ext.db.INTEGER, Ext.db.ForeignKey('company.id'))
company = Ext.db.relationship('Company', backref=Ext.db.backref('user'))
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
初始化
根据上述对表的定义,删除所有表,创建所有表
db.drop_all()
db.create_all()
DML
SQLAlchemy需要多使用,多探索,非常高效灵活,我甚至一度想参照SQLAlchemy的实现往Java社区输送一个类似的数据库管理产物,来替代MyBatis。
新增,修改(如果带id的话就是修改)
db.session.add(guest)
db.session.commit()
查
SQLAlchemy的查询构建非常灵活,由于Python动态语言特性,有一些方法不会在IDE的代码提示中显示,只有执行的时候才会体现一方面使用可以参照官方文档,另外一方面可以在交互式窗口或者调试窗口中,动态、交互地探索相应的方法。
下面列出常用的几种查询方式供大家参考:
# 查询所有
users = User.query.all()
# 单表条件查询
admin = User.query.filter_by(username='admin').first()
# 关联查询1
db.session \
.query(Article) \
.join(User, User.id == Article.user_id) \
.filter(User.username == "bitekong") \
.all()
# 复杂条件关联查询
Role.query \
.join(User, User.id == Role.user_id) \
.join(Resource, Resource.id == Role.resource_id) \
.filter(
and_(
or_(
and_(Resource.needs_permission == True,
User.id == session.get("user_id")),
(Resource.needs_permission == False)
)
),
Resource.path == request.path) \
.first()
# in的使用
Resource.query.filter(Resource.path.in_(sys_paths)).all()
# 内置方法的使用
db.session \
.query(Article.title.label("title"),
func.substr(Article.content, 0, 10).label("content")) \
.all()
6. 更多
上述只是简单地介绍了一下Flask的使用,其实在实际工程中有很多需要考量的地方。如果感兴趣可以了解一下如下内容,对使用Flask会有很大的帮助,我也会相继在我的CSDN中更新。
- 蓝图(BluePrint)
- Flask-JSON
- Flask-Migrate
- View、Model自动化构建
- Flask实战
我通常是用FLask作为Web后台来使用,前端通常使用React来构建,所以jinja2等模版框架鲜有涉及,在前日益提倡后端分离的今天,jinja2等模版的市场会越来越小,但用来写一点快速的后台管理还是很方便的。
抛砖引玉,才疏学浅,如有纰漏,欢迎指正。