对于Web后台开发,Java企业级框架SpringBoot当之无愧的王者,无论从执行效率还是从扩展性上面来说都是实实在在的企业级选择。正因为其兼顾太多方面,体系复杂而庞大,十分不适合一些需要轻量化的场景。另外对于不熟悉Java的同学来说,去理解SpringBoot的整个体系是需要足够多的时间成本的。
在Python中,我十分推荐使用Flask来构建web后台应用。理由有如下几个:
gunicorn
(一个Python的Http服务器),Qps居然可以达到4000。FLask
作为Web后台
来使用,前端通常使用React
来构建,所以jinja2
等模版框架鲜有涉及。在前日益提倡后端分离的今天,jinja2
等模版的市场会越来越小,但用来写一点快速的后台管理还是很方便的。聊了那么多,下面我们开始FLask
的旅程!
下面就是一个完整的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
我们来对代码进行一一解读
from flask import Flask
app = Flask(__name__)
导入Flask
包,构建Flask
类,其中有疑问的很可能是为什么要传递__name__
参数,这是因为Flask会根据__name__
来区分所在包。官方文档中提到,当你只使用单模块时,Flask(__name__)
肯定是正确的。如果Flask
应用是一个包,那么建议此处硬编码为包名字。一般都是传递__name__
。
@app.route("/")
def home():
return "Hello World"
熟悉Springboot
的同学就知道,这就是赤裸裸的Controller
的RequestMapping
呀。@
是python
装饰器,如果不了解装饰器的同学可以看我另外一篇文章,浅谈Python装饰器。
你只需要知道此处将home
函数映射到/
这个目录即可,当通过Http访问/
,则会执行home
函数,并将返回值作为Response返回给Http的请求方。
if __name__ == "__main__":
app.run(debug=True)
运行参数默认为:
host
: localhost
,如果需要外网访问需要显式指定host='0.0.0.0'
port
: 5000
debug
: False
,debug参数为我们提供了编写代码时候的热加载功能,可以及时看到修改代码产生的效果,建议开启。在部署正式环境的时候需要将其修改为False
(实际上不用,因为gunicorn调用Flask根本不会走__main__
这块)。现在就打开浏览器输入http://localhost:5000
看看效果吧。
简单使用:
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
相信根据上述的学习,已经可以构建一个基本的可以相应外部请求的FLask应用了。
接下我们要引入数据库组件:SQLAlchemy
。
数据库我们暂时用sqlite来进行学习,实际使用只需要把对应的连接字符串修改为你所使用的数据库对应的即可,我会给出示例。不知道你有没有发现,Flask很容易就能使用不同的数据库,而不需要额外的编码。
安装
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 '' % self.username
根据上述对表的定义,删除所有表,创建所有表
db.drop_all()
db.create_all()
SQLAlchemy需要多使用,多探索,非常高效灵活,我甚至一度想参照SQLAlchemy的实现往Java社区输送一个类似的数据库管理产物,来替代MyBatis。
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()
上述只是简单地介绍了一下Flask的使用,其实在实际工程中有很多需要考量的地方。如果感兴趣可以了解一下如下内容,对使用Flask
会有很大的帮助,我也会相继在我的CSDN中更新。
我通常是用FLask
作为Web后台
来使用,前端通常使用React
来构建,所以jinja2
等模版框架鲜有涉及,在前日益提倡后端分离的今天,jinja2
等模版的市场会越来越小,但用来写一点快速的后台管理还是很方便的。
抛砖引玉,才疏学浅,如有纰漏,欢迎指正。