sqliteflask starter: tadpole

tadpole 是一个flask starter
项目。从平常flask项目之支出过程被取出来的一对通用的力量,如通过gunicorn管理flask应用的布局文件与开行脚本,初始化virtualenv环境而设置必要的依库,生成flask
secret以及供restful route, 自动吗sqlalchey model注册restful接口,
登录认证,权限管理, restful支持等等技能。

如出一辙、系统及环境要求

posix, Python 2.x >= 2.6

亚、 安装方式

pip install tadpole

三、git地址

https://github.com/echoyuanliang/tadpole

迎接pull request, 一起抓好是类型, 如果觉得不错, 欢迎star。

季、 使用办法

tadpole init -n PROJECT_NAME -v PROJECT_VERSION -o PROJECT_OWNER -e PROJECT_EMAIL

其中PROJECT_NAME大凡初始化的路名为,PROJECT_VERSION举凡初始化的版本号(默认为0.0.1),
PROJECT_OWNER啊项目负责人,
PROJECT_EMAIL否品种邮件组(用于吸纳邮件)。

为可以直接执行tadpole init 会提示填写入路名为,其他以默认, 例如:

tadpole-init

五、项目组织

至今,已经使用tadpole初始化了一个初的flask项目,进入tadpole-demo目录可以看到

demo-struct

  • requirements.txt
    新类型依赖第三正值库列表(其中蕴涵了flask项目常用依赖库)
  • venv 为新类型变更的virtualenv
    环境,其中都装了requirements.txt中宣称的负项
  • main.py 项目进口文件,其中定义了Flask app
  • app 主要代码目录
  • config.py 配置文件(会上传git,主要含有无涉秘配置起)
  • instance 其中由instance/config.py, 本地配置起,已经加入.gitignore,
    不会上传git,其中也涉密配置或者本地特殊安排,其中安排可以覆盖config.py中配置
  • gun.py gunicorn配置文件
  • data 项目数量目录,已经加入.gitignore
  • logs 项目日志目录,已经加入.gitignore
  • dev
    本地调试管理脚本,由于有项目的有权力,因此都加入.gitignore,仅供本地调试
  • tadpole-demo
    因档名gunicorn管理脚本,提供了gunicorn启动/停止/重新加载等技术

六、管理脚本的行使

6.1 dev的使用

dev是供给开发者在付出环境下利用的家伙,其中提供了之类技术

  • create_db: 根据model自动生成表结构
  • url: 展示所有注册url
  • clean: 删除项目目录下拥有pyc,pyo文件
  • shell: 以令执行措施侵入应用
  • runserver: 使用flask内置的web服务器在5000端口启动以

这里就盖 url 为例:

dev-url

得视新初始化的类曾发出诸如此类多报的url了,其中prefix为/api/v0.0.1/rest_db开头的url都是啊曾经创造的
user,role,resource三张表自动生成的restful
api。另外一个/health则用于健康检查。最后的/static/则是flask默认提供的。

6.2 tadpole-demo的使用

  • start 用gunicorn启动flask应用,如:

demo-start

  • status 用于展示gunicorn应用状态,如:

demo-status

  • stop 用于停止gunicorn应用
  • reload
    用于更加载gunicorn配置文件,同时又启航worker进程(目前才支持linux,不支持mac)

七、提供的基本技能

7.1 sqlalchemy restful model

工作备受常会面有人如果接口查询数据,但是洋洋数量才待实施sql语句就会拿到多少,但是还要休克一直拿DB权限给别人,
为此提供了一个管简单sql语句自动对承诺交restful查询的艺。这个技术实际上市场上曾闹许多仓库提供了,但是
并无遇上被自己好用之慌舒适的库,因此好写了一个,这个技术的徒待用户写Model类,并一直或者间接的
import到app/models/init.py中即可为该机动注册restful接口。

为了初始化出来的路可以开箱即用,
会给默认的db(sqlite数据库,文件在app.db)中创造user,role,resource等
表结构,同时会插入部分数据,因此访问已经报之rest_db
url是得直接拿到数码的, 例如:

curl http://127.0.0.1:8080/api/v0.0.1/rest_db/user 

{
    "code": 200,
    "msg": "ok",
    "result": {
        "next_page": "http://127.0.0.1:8080/api/v0.0.1/rest_db/user?__page=2&__page_size=200",
        "page": 1,
        "page_size": 200,
        "prev_page": null,
        "result": [
            {
                "__roles_link": "http://127.0.0.1:8080/api/v0.0.1/rest_db/user/1/roles",
                "account": "tadpole",
                "create_time": "2017-11-26 17:53:13",
                "email": "tadpole@tadpole.com",
                "id": 1,
                "name": "tadpole"
            }
        ]
    }
}

可见到user表已经起雷同漫漫记下了,同时__roles_link链接到了每个用户所持有的角色,直接看可以看来

curl http://127.0.0.1:8080/api/v0.0.1/rest_db/user/1/roles 


{
      "msg": "ok",
      "code": 200,
      "result": {
        "next_page": "http://127.0.0.1:8080/api/v0.0.1/rest_db/user/1/roles?__page=2&__page_size=200",
        "prev_page": null,
        "result": [
          {
            "description": "super admin",
            "__resources_link": "http://127.0.0.1:8080/api/v0.0.1/rest_db/role/1/resources",
            "__users_link": "http://127.0.0.1:8080/api/v0.0.1/rest_db/role/1/users",
            "create_time": "2017-11-26 17:42:52",
            "id": 1,
            "name": "root"
          }
        ],
        "page_size": 200,
        "page": 1
     }
}

足见见tadpole这个用户都怀有了一个root角色,
每一样长条记下除了回到自己之的排列之外还坐__{relation}_link的款式返回了其干关系的链接。

7.1.1 支持之询问条件

 OPERATORS = ('lt', 'le', 'gt', 'ge', 'eq', 'like', 'in', 'between')
PROCESSES = ('__show', '__order')
PAGINATE = ('__page', '__page_size')

询问条件分为3类,一看似是基本的运算符在OPERATORS中,另一样像样是指向查询的数量进行部分拍卖,如排序、只展示部分列等,另一样接近则是分页。
联手使用这些查询条件:

curl http://127.0.0.1:5000/api/v0.0.1/rest_db/user?name=tadpole&account.like=tad%&__show=account,email&__order=id.asc,name.desc 
{
  "msg": "ok",
  "code": 200,
  "result": {
    "next_page": "http://127.0.0.1:5000/api/v0.0.1/rest_db/user?name=tadpole&__page_size=200&__page=2&account.like=tad%25&__order=id.asc%2Cname.desc&__show=account%2Cemail",
    "prev_page": null,
    "result": Array[1][
      {
        "account": "tadpole",
        "email": "tadpole@tadpole.com"
      }
    ],
    "page_size": 200,
    "page": 1
  }
}

足见到仅返回了__show遭到列有的排列,而且按照name=tadpole,account.like=tad%过滤的结果,并且根据__order遭遇的排序条件进行了排序。

7.1.2 url规则

得视生成的url都是生必然规则的,
prefix为/api/v0.0.1,其中v0.0.1凡项目之本子号,但是是是可定制的。通过部署文件中之BP_PREFIX就足以配备各级一个bluprint对应之prefix,例如rest_db这个blueprint(即rest
model使用的)的安排好如下:

BP_PREFIX = {
'rest_db': '/api/{0}/rest_db/'.format(VERSION)
}

除外prefix之外,后面紧跟着的虽是表名,如果是涉嫌查询则是{prefix}/{table_name}/{pk_id}/{relation_name}

7.1.3 自动隐藏

连无是具备的列都适合展示,有些列(比如密码,并无称对外开放),初始化出来的色针对user表的password列就召开了隐形,如下:

class User(Model):

# columns in __hide__ does'nt show in rest_db
__hide__ = ('password',)

account = Column(
    db.String(128),
    nullable=False,
    default=u'-',
    index=True,
    unique=True)
name = Column(db.String(32), nullable=False, default=u'-')
email = Column(db.Email(128), nullable=False, default=u'-')
password = Column(db.Password(schemes=['pbkdf2_sha512', 'md5_crypt'],
                              deprecated=['md5_crypt']), nullable=False, default=u'-')

声明Model时, __hide__元组中之排非会见以自动生成的restful接口中展示

7.2 登录控制与权力管理

对此各级一个运用来说,都发生非符合对富有人数放之资源,因此要登录控制及权杖管理。tadpole默认在app/models/auth包中实现了用户和权力依赖的Model,
于app/lib/auth.py中落实了关于报到和权力验证的逻辑。登录验证时利用的是Http Basic征,
因为密码是单纯为加密囤积的,所以有些证措施(如Http Digest)不能够一直用,有需要可以对代码进行扩张。扩展为异常轻,有趣味的朋友可看实现源码进行扩张。权限校验则是简约的查询数据库看用户产生没发出对某个一样资源执行某平等操作的权能(此处为可好轻扩展自己的校验方式),权限校验默认对restful接口的http
method进行了支撑,因此才需要在数据库被补充加合适的笔录既可以成功接口的权决定。为了采取得开箱即用,已经对/api/v0.0.1/rest_db/始发的url做了权限制,其POST,DELETE,PUT术只有发生root权限用户可以操作,如:

role_resource

user_role

对新初始化的色,已经补给加了account=tadpole-demo,password=12qwaszx的用户,并且给予了root角色,可以实行POST /api/v0.0.1/rest_db/*测试权限校验是否对。

止需要将resource 和
role关联起来便好独自开给对许角色的用户。数据库被绝非记录之resource以及无关联role的resource是对有人数开之。一个资源开放给的用户是资源名称可以正则相当的交有resource.name,且对资源的操作以resource.operation(用’,’分割)中之资源列表所开放为的角色所兼有的用户。
例如对于http restful接口的权力校验, 会拿出有匹配path 和
method的resource,然后查询这些resource开放的role列表,要求用户只有满足所有这些role,才好看对应接口。

7.3 关于rest_route

对此restful接口来说,
一是参数的校验几乎都亟需,二凡盼得以回去python对象,由框架自动处理成json格式。rest_route对这些做了支撑。
如:

from main import app


validator = {
    'required': ['user_name']
}


@app.rest_route('/welcome', methods=['GET'], validator=validator)
def welcome(data):
    return 'hell0', data['user_name']

率先validator中得针对参数进行校验,默认实现了几种常用校验,也足以自己扩大,除此之外还落实了custom校验,即传入用户自己的校验函数,这段代码提供了针对性user_name参数必填的校验。除此之外,为了供合的交由数据输入,所有提交数据都为merge到data参数中了,rest_route接口的POST方法要付出json格式数据。最后回来一个元组,在rest_route中会自行将那个转化为json
list,请求是接口返回如下:

curl http://127.0.0.1:5000/welcome


{
  "msg": "param user_name is required",
  "code": 400
}


curl http://127.0.0.1:5000/welcome?user_name=tadpole

{
  "msg": "ok",
  "code": 200,
  "result": Array[2][
    "hell0",
    "tadpole"
  ]
}

归来结果不仅支持直接返回元组,还支持sqlalchemy查询结果一直归,set返回等等。对于用户从定义的靶子要如支持直接回到,只待贯彻to_dict/_as_dict方法以对象转化成dict即可。

7.3.1 默认支持的参数校验方式

参数校验是透过app/lib/validator实现的,有趣味之爱侣可一直扣源码,实现深简短,也堪友善壮大。目前兑现之校验方式发出以下:

  • required: 必填参数列表, 用户要填写充但可以为空字符串. 数据类型为list
  • nonempty: 必填且不克吧空参数列表。数据类型为list
  • types: 参数类型校验, 数据类型为dict,例如:

    validator = {
        'types': {
            'age': int,
            'active': bool,
        }
    }
  • oneof:
    如果参数名称在oneof中,其值必须使属oneof[param_name]着之一个,数据类型为dict
  • unique: 对list类型参数做去重新,数据类型为list
  • length: 对参数长度组校验, 数据类型为dict
  • default: 对参数提供默认值, 数据类型为list
  • override: 用对参数处理后底结果取代参数的价值,数据
  • custom: 用户从定义校验方法,数据类型为list

例如:

validator = {
    'required': ['task_id'],  # 必填参数

    'nonempty': ['project', 'env', 'ip_list', 'component'], # 不能为空

    'types': {
        'ip_list': list,
        'mem': int
    },

    'unique': ['ip_list'], # 对ip_list参数去重

    'default': {
        'region': 'Shanghai' # 如果用户没有填写region参数,则用Shanghai填充
    },

    'oneof': {
        'region': ['Shanghai', 'Beijing'], # region参数必属于Shanghai和Beijing之一
    }
}

7.3.2 关于大处理

都落实了好的电动捕捉,并返回合适的音,默认提供的坏在app/lib/exceptions.py中,
负有继续自CustomError的死去活来都见面受捕捉,并且返回msg作为错误信息,code作为返回码,因此可以直接抛出这些杀给用户,
不欲更展开拍卖。也得以扩展自定义之不胜。默认异常定义示例:

class CustomError(Exception):

def __init__(self, msg):
    super(CustomError, self).__init__(msg)
    self.msg = msg
    self.code = 500

def to_dict(self):
    return dict(code=self.code, msg=self.msg)

def __unicode__(self):
    return unicode(self.msg)

def __str__(self):
    return str(self.msg)


class InternalError(CustomError):

    def __init__(self, msg):
        super(InternalError, self).__init__(msg)
        self.code = 500
网站地图xml地图