官方文档
使用flask-appbuilder创建一个简单的项目,它是一个基于Flask的web框架,实现了数据的自动CRUD,登录等角色权限管理。
pip install flask-appbuilder
# 帮助信息
flask --help
flask routes # 查看所有的路由
flask run # 运行开发服务器 --help
flask shell # 进入shell命令行
flask fab # fab 命令组
flask db upgrade # 同步数据库
flask fab --help # 帮助信息
babel-compile Babel, Compiles all translations
babel-extract Babel, Extracts and updates all messages marked for...
collect-static Copies flask-appbuilder static files to your...
create-addon Create a Skeleton AddOn (needs internet connection...
create-admin Creates an admin user
create-app Create a Skeleton application (needs internet...
create-db Create all your database objects (SQLAlchemy...
create-permissions Creates all permissions and add them to the ADMIN...
create-user Create a user
export-roles Exports roles with permissions and view menus to...
import-roles Imports roles with permissions and view menus from...
list-users List all users on the database
list-views List all registered views
reset-password Resets a user's password
security-cleanup Cleanup unused permissions from views and roles.
security-converge Converges security deletes...
version Flask-AppBuilder package version
使用flask fab管理命令,快速创建应用程序。
# 快速创建应用程序
flask fab create-app
# 输入项目名等
# __author__ = "laufing"
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# openssl rand -base64 42 生成秘钥
SECRET_KEY = "ulaO869huOl68ZhTZiNcOIq9zxwTSLd/LH40bv69IyUcb1xRssbAMrol"
SQLALCHEMY_DATABASE_URI = f"sqlite:///{BASE_DIR}/lauf.db"
# app 中
app/__init__.py
app = Flask(__name__)
app.config.from_object("config") #自动搜索config.py 进行配置
# views中
from flask_appbuilder import IndexView, BaseView
class MyIndexView(IndexView):
index_template = "tindex.html"
在_init_.py中导入定义的视图
from .views import *
# 获取数据库接口
db = SQLA(app)
appbuilder = AppBuilder(app, db.session, indexview=MyIndexView)
使用蓝图扩展用户模块,创建一个用户目录。
# user > 编写views.py
from flask import request, session, current_app, g, jsonify
from flask_appbuilder import BaseView, expose, has_access
from app import appbuilder, db
class UserView(BaseView):
# 进入蓝图的基本路由
route_base = "/user"
# 默认视图
default_view = "index" # 函数名,添加视图时,可以不指定href,请求时,匹配到default_view
@expose("/index", methods=["GET"])
def index(self):
return "用户首页"
@expose("/api", methods=["GET"])
def get(self):
return jsonify({
"name": "jack",
"age": 12
})
@expose("/api", methods=["POST"])
def post(self):
print("提交的数据:", request.form)
return jsonify({
"token": "xyz123"
})
# 添加视图、菜单
appbuilder.add_view(UserView, "user index", category="User View") # 没有href, 请求/user/index时走默认视图
appbuilder.add_view(UserView, "user menu", href="/user/api", category="User View")
# 在 run.py (汇总) 中导入所有的视图
from app import app
from user.views import * # 必须导入,或者在这里添加视图
app.run(host="0.0.0.0", port=5050, debug=True)
# 设置环境变量
set FLASK_APP=run.py
# 启动服务
# 代码更新,自动加载 --reload
# 开启子线程 --with-reloads
flask run -h localhost -p 5050 --reload --with-threads --debugger
浏览器中可以进行简单测试。
创建模型类
# user > models.py
from flask_appbuilder import Model
from sqlalchemy import Column, String, Integer
class MyModel(Model):
# 表名
__tablename__ = "my_model_t"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), unique=True, nullable=False)
# print info when print this obj
def __repr__(self):
return self.name
# 将模型类导入app.__init__.py
db.create_all() # 创建所有的表
修改视图
,实现数据的插入、查询。
class UserView(BaseView):
# 进入蓝图的前缀
route_base = "/user"
# 默认视图
default_view = "index" # endpoint 函数名
@expose("/index", methods=["GET"])
def index(self):
# 获取会话
session = db.session # db = SQLA(app)
m_obj = session.query(MyModel).filter_by(id=1).one_or_none() # all()获取所有对象
print("result:", m_obj, type(m_obj))
return jsonify({
"status": 200,
"id": m_obj.id,
"name": m_obj.name
})
@expose("/api", methods=["GET"])
def get(self):
return redirect("/user/index")
@expose("/api", methods=["POST"])
def post(self):
print("提交的数据:", request.form) # requests.post(url, data=data)
# 若requests.post(url, json=data)
# request.json 属性 必须对应
name = request.form.get("name")
session = db.session
# 实例化数据对象
m = MyModel(name=name)
# 添加到数据库
session.add(m)
session.commit()
return jsonify({
"status":200,
"message": f"添加{name}成功"
})
appbuilder.add_view(UserView, "user index", category="User View")
appbuilder.add_view(UserView, "user view", href="/user/api", category="User View")
启动项目,可以进行简单测试。
get /user/api
post /user/api
from sqlalchemy import Column, String, Integer, PrimaryKey, Text, Date, Time, DateTime, create_engine
from sqlalchemy.orm import relationship
# 联系人的 分组表 main table
class Group(Model):
"""
tablename:
group_t
fields:
id, int pk
name, varchar(30) unique not null
"""
__tablename__ = "group_t" # 定义关系时使用,默认的表名为模型类小写 + _
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(30), unique=True, nullable=False)
# 主表定义关系
# concat_relation = relationship("Concat", backref="concats", uselist=False)
# 联系人 表 sub table
class Concat(Model):
"""
table name:
concat_t
fields:
id, int pk
name, varchar(50) unique not null
phone, varchar(11) not null
group_id, int fk
"""
# table name
__tablename__ = "concat_t"
# primary key
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), unique=True, nullable=False, doc="姓名")
phone = Column(String(11), nullable=False, doc="手机号")
# foreign key
# fk reference main table
group_id = Column(Integer, ForeignKey("group_t.id")) # 引用 主表名.id
# 定义关系
# Group为主表模型类
# backref 反向查询的名字
group = relationship("Group", backref="concats", uselist=False)
def __repr__(self):
return self.name
将模型类导入app._init_.py, 重启项目即可创建出所有的表。
在flask shell 下可以进行简单测试:
>>> from app import db
>>> from user.models import Group, Concat
>>> grp1 = Group(id=1, name="家人")
>>> session = db.session # 自动开启事务
>>> session.add(grp1)
>>> session.commit()
>>> c1 = Concat(id=1, name="b1", phone="17446534545", group_id=1)
>>> c2 = Concat(id=2, name="b2", phone="17876543454", group_id=1)
>>> session.add(c1)
>>> session.add(c2)
>>> session.commit()
# 返回查询
>>> grp1.concats
[b1, b2]
# 正向查询
>>> c1.group/group_id
<user.models.Group object at 0x00000215A0ECA100>
>>> c1.group.name
'家人'
可在视图中自己实现CRUD, 略
基于flask_appbuilder 实现自动的CRUD,定义模型类视图。
from flask_appbuilder import ModelView
from flask_appbuilder.models.sqla.interface import SQLAInterface
from .models import Group, Concat
class ConcatModelView(ModelView): # 管理后台页面
datamodel = SQLAInterface(Concat)
# 定义 视图页面显示的列名称
label_columns = {'group_id': 'Concats Group ID', "name": "Concat Name"}
# 列表视图 显示的列 /concatmodelview/list/
list_columns = ["id", "name", "phone", "group_id"]
# show视图(一条数据) 显示的列 /concatmodelview/show/pk
show_columns = ["id", "name"]
# 搜索字段
search_columns = ['name',]
# show 视图展示的格式 /concatmodelview/show/1 优于show_columns
show_fieldsets = [
( # 每一部分都是一个元祖
'Summary1111111', # 标题
{'fields': ['name', 'group_id']}
),
(
'Personal Info',
{'fields': ['phone',], 'expanded': False}
),
]
class GroupModelView(ModelView):
datamodel = SQLAInterface(Group) # input a model
related_views = [ConcatModelView]
# 添加 模型视图 自动路由
appbuilder.add_view(GroupModelView, "Group menu", category="GroupModelView", icon = "fa-folder-open-o")
appbuilder.add_view(ConcatModelView, "Concat menu", category="ConcatModelView", icon = "fa-envelope")
# 为ConcatModelView 自动添加的路由
# flask_appbuilder.base:Registering class ConcatModelView on menu Concat menu
# flask_appbuilder.baseviews:Registering route /concatmodelview/action// ['GET', 'POST']
# flask_appbuilder.baseviews:Registering route /concatmodelview/action_post ['POST']
# flask_appbuilder.baseviews:Registering route /concatmodelview/add ['GET', 'POST'] 添加 页面
# flask_appbuilder.baseviews:Registering route /concatmodelview/api ['GET'] api返回所有联系人的json数据
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/column/add/ ['GET']
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/column/edit/ ['GET']
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/create ['POST'] 添加一个联系人
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/delete/ ['DELETE'] 删除一个联系人
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/get/ ['GET'] 获取一个联系人
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/read ['GET'] 获取所有联系人 json
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/readvalues ['GET'] 获取少许字段
# flask_appbuilder.baseviews:Registering route /concatmodelview/api/update/ ['PUT'] 更新一个
# flask_appbuilder.baseviews:Registering route /concatmodelview/delete/ ['GET', 'POST'] 删除一个
# flask_appbuilder.baseviews:Registering route /concatmodelview/download/ ('GET',)
# flask_appbuilder.baseviews:Registering route /concatmodelview/edit/ ['GET', 'POST'] 编辑联系人页面
# flask_appbuilder.baseviews:Registering route /concatmodelview/list/ ('GET',) 视图页面
# flask_appbuilder.baseviews:Registering route /concatmodelview/show/ ['GET'] 视图页面
show_fieldsets
add_fieldsets、edit_fieldsets,可以自定义显示的字段格式。
对模型视图
的CRUD必须登录。
启动服务,测试增删改查。
# 设置环境变量
set FLASK_APP=run.py
# flask run --help
flask run -h localhost -p 5050 --reload --with-threads
浏览器中访问 http://localhost:5050 加对应的路由地址,综合测试。
gunicorn官方文档
# 使用pip包管理工具,安装到python环境中
pip install gunicorn
# 安装协程并发库,linux下需要安装apt install python-dev libevent
pip install gevent eventlet
另外也可以使用源码安装。
Ubuntu 20.04默认仓库就带有gunicorn,可以如下直接安装:
$ sudo apt-get update
$ sudo apt-get install gunicorn
# config_gunicorn.py 它是一个python文件
# 绑定主机地址
bind='0.0.0.0:8000' # 局域网ip 或者公网内的局域网
# 注意没有port选项
其他更多配置项参考
# 开启三个worker进程
gunicorn -w 3 -b 0.0.0.0:8000 my_flask_project.app:app
# 使用.表示路径,找到对应的模块
# 使用:拼接模块中的app对象
# 也可以my_flask_project.app:create_app() 工厂函数执行
# 默认加载当前目录下的gunicorn.conf.py
# 创建一个配置文件
# config_gunicorn.py 命令行-c xxxconfig.py 指定配置文件
bind='0.0.0.0:8000' # 绑定ip地址 命令行下用--bind ip:port
daemon='true' # 后台启动 命令行 --daemon
worker_class='gevent' # worker进程的类型 命令行下 -k
workers=4 # 开启4个worker进程
threads=4 # 每个worker进程中4个线程
# 日志输出
loglevel='info'
accesslog='logs/access.log'
errorlog='logs/error.log'
启动flask
# 使用gunicorn启动flask应用
gunicorn -c config_gunicorn.py package.module:app