Flask----flask-appbuilder + 项目部署

文章目录

  • flask-appbuilder
    • 安装
    • 创建应用程序
    • 编写首页视图
    • 编写用户视图
    • 编写模型类
    • 模型自动的CRUD
    • 启动项目
  • WSGI服务部署
    • gunicorn + flask 部署

flask-appbuilder

官方文档
使用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
# 输入项目名等

在这里插入图片描述
 

编写首页视图

  • 配置,在项目根目录下添加config.py,一般会自动创建出来。
# __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 进行配置
  • 编写首页视图
    Flask----flask-appbuilder + 项目部署_第1张图片
# 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, 略

模型自动的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
Flask----flask-appbuilder + 项目部署_第2张图片
add_fieldsetsedit_fieldsets,可以自定义显示的字段格式。
模型视图的CRUD必须登录。
 

启动项目

启动服务,测试增删改查。

# 设置环境变量
set FLASK_APP=run.py

# flask run --help
flask run -h localhost -p 5050 --reload --with-threads

浏览器中访问 http://localhost:5050 加对应的路由地址,综合测试。
 

WSGI服务部署

  • wsgi: web server gateway interface
  • python实现的web应用框架,部署时基本都是使用WSGI服务器进行部署,如部署django使用uwsgi,部署flask可以使用gunicorn。
  • gunicorn 支持python的web框架,自动worker进程管理,要求python 3.5+
     

gunicorn + flask 部署

gunicorn官方文档

  1. 安装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
  1. 配置项介绍
    可以在配置文件中使用,也可以在命令行中使用。
# config_gunicorn.py  它是一个python文件

# 绑定主机地址
bind='0.0.0.0:8000'  # 局域网ip  或者公网内的局域网
# 注意没有port选项

其他更多配置项参考
 

  1. gunicorn 启动flask
  • 命令行
# 开启三个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

你可能感兴趣的:(Flask系列,flask,python,后端)