Commit 783c1ee7 authored by wanli's avatar wanli

update

parent 0abaea48
......@@ -5,17 +5,13 @@ import os
import re
import shutil
import copy
import time
import types
import json
import logging
import traceback
from urllib import parse
from datetime import datetime
from pony.orm import *
from app import signalManager, config
from model import fullStackDB
from model.annex import Annex
from model.apps import Apps
from model.user import User
......@@ -83,7 +79,7 @@ class AppsManager(object):
if app_info:
app_info['md5'] = str(app_info['md5'])
result = BuildLogs(app=app, app_path=epk_filename, app_info=app_info, create_by=editor, create_at=datetime.now(), update_by=editor, update_at=datetime.now())
result = BuildLogs(app=app, app_path=epk_filename, app_info=app_info, source=1, create_by=editor, create_at=datetime.now(), update_by=editor, update_at=datetime.now())
commit()
AppLogs(app_name=app.app_name, app_path=epk_filename, app_version=data.get("app_version"), app_info=app_info, create_by=editor, create_at=datetime.now())
commit()
......@@ -200,6 +196,12 @@ class AppsManager(object):
for item in result:
temp.append(item.to_dict(only=["uuid", "app_name"]))
return temp, len(temp), "get app {}.".format("success" if temp else "fail")
elif "scope_type" in data and data.get("scope_type") == "distinct":
result = select(p.category for p in Apps)
temp = []
for item in result:
temp.append(item)
return temp, len(temp), "success"
result = Apps.select().where(**temp).order_by(Apps.sort).sort_by(desc(Apps.create_at)).page(data.get("pagenum", 1), pagesize=data.get("pagesize", 10))
count = Apps.select().where(**temp).count()
......@@ -270,7 +272,9 @@ class AppsManager(object):
if not user:
return False, "user does not exists"
if data.get("access_key"): data.pop("access_key")
if data.get("access_key"):
data.pop("access_key")
data.update({
'create_by': user,
'create_at': datetime.now(),
......@@ -317,7 +321,7 @@ class AppsManager(object):
build.set(app_path=epk_path, app_info=app_info, update_by=user, update_at=datetime.now())
commit()
else:
BuildLogs(app=app, app_path=epk_path, app_info=app_info, create_by=user, create_at=datetime.now(), update_by=user, update_at=datetime.now())
BuildLogs(app=app, app_path=epk_path, app_info=app_info, source=2, create_by=user, create_at=datetime.now(), update_by=user, update_at=datetime.now())
commit()
# 新增一条AppLogs
......
<template>
<div class="app-container">
<el-form :inline="true" ref="form" :model="form" size="mini">
<el-form-item label="应用名称" prop="uuid">
<el-select v-model="form.uuid" filterable placeholder="请输入标题">
<el-option
v-for="(item, index) in selectList"
:key="index"
:label="item.app_name"
:value="item.uuid"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="应用分类">
<el-select v-model="form.category" filterable placeholder="请选择分类">
<el-option
v-for="(item, index) in categoryList"
:key="index"
:label="item"
:value="item"
></el-option>
</el-select>
</el-form-item>
<el-form-item
><el-button type="primary" @click="onSubmit"
>查询</el-button
></el-form-item
>
<el-form-item
><el-button type="warning" @click="onAdd"
>添加应用</el-button
......@@ -220,10 +245,13 @@ export default {
imageUrl: "",
total: 0,
list: [],
selectList: [],
categoryList: [],
isLoading: false,
form: {
uuid: null,
name: null,
category: null,
pagesize: 15,
pagenum: 1,
},
......@@ -276,6 +304,13 @@ export default {
this.isLoading = false;
});
},
fetchCategory() {
getAppsList({ scope_type: "distinct" }).then(res => {
this.categoryList = res.data
}).catch(err => {
console.log(err.message)
})
},
handleSizeChange(e) {
this.form.pagesize = e;
this.fetchData(mapTrim(this.form));
......@@ -368,6 +403,15 @@ export default {
this.imageUrl = null;
this.post.logo = file.file;
},
fetchSelectData() {
getAppsList({ scope_type: "list" })
.then((res) => {
if (res.code == 200) this.selectList = res.data;
})
.catch((err) => {
console.log(err.message);
});
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
let result = true;
......@@ -440,6 +484,8 @@ export default {
mounted() {},
created() {
this.fetchData(mapTrim(this.form));
this.fetchSelectData();
this.fetchCategory();
},
};
</script>
......
......@@ -4,9 +4,9 @@
<el-form-item label="应用名称" prop="uuid">
<el-select v-model="form.uuid" filterable placeholder="请输入标题">
<el-option
v-for="(item, index) in roles"
v-for="(item, index) in selectList"
:key="index"
:label="item.name"
:label="item.app_name"
:value="item.uuid"
></el-option>
</el-select>
......@@ -34,6 +34,12 @@
min-width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="source_text"
label="打包来源"
width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="app_path"
label="应用路径"
......@@ -93,7 +99,7 @@ export default {
total: 0,
list: [],
isLoading: false,
roles: [],
selectList: [],
form: {
uuid: null,
name: null,
......@@ -129,7 +135,11 @@ export default {
getAppLogsList(params)
.then((res) => {
this.total = res.count;
this.list = res.data;
this.list = res.data.map(item => {
if (item.source == 1) item.source_text = "后台";
else if (item.source == 2) item.source_text = "接口";
return item;
});
})
.catch((err) => {
// this.$message.error(err.message)
......@@ -142,7 +152,7 @@ export default {
fetchSelectData() {
getAppLogsList({ scope_type: "list" })
.then((res) => {
if (res.code == 200) this.roles = res.data;
if (res.code == 200) this.selectList = res.data;
})
.catch((err) => {
// this.$message.error(err.message)
......
......@@ -69,7 +69,7 @@ export default {
})
.then(({ value }) => {
if (value) this.filename = value;
this.createFile(this.outputString, `${this.filename}.c`);
this.createFile(this.outputString, this.filename);
})
.catch(() => {
this.$message({
......
......@@ -8,3 +8,62 @@
- https://flask-sqlalchemy.palletsprojects.com/en/2.x/
- http://www.pythondoc.com/flask-sqlalchemy/index.html
- https://jinja.palletsprojects.com/en/2.11.x/templates/
- marshmallow: https://www.cnblogs.com/dowi/p/11850558.html
- https://flask-marshmallow.readthedocs.io/en/latest/
- https://docs.pyfilesystem.org/en/latest/index.html
- https://jinja.palletsprojects.com/en/3.0.x/
# 问题
## ModuleNotFoundError: No module named 'flask._compat'
解决方法:
```
On this specific error: from flask._compat import text_type
ModuleNotFoundError: No module named 'flask._compat' -
It happened because the python searched on Flask._compat directory and It isn't there, so I changed like on below : (on flask_script/__init__.py)
Where:
`from ._compat import text_type` on original flask-script file
to :
`from flask_script._compat import text_type`
Then It works !!
```
## ModuleNotFoundError: No module named 'fcntl'
解决方法:
输入以下代码并保存至Python安装目录的Lib目录下
```
LOCK_UN=8
LOCK_EX=2
F_GETFD=1
FD_CLOEXEC=1
F_SETFD=2
def fcntl(fd, op, arg=0):
return 0
def ioctl(fd, op, arg=0, mutable_flag=True):
if mutable_flag:
return 0
else:
return ""
def flock(fd, op):
return
def lockf(fd, operation, length=0, start=0, whence=0):
return
```
\ No newline at end of file
# Flask-Migrate
数据库迁移工具:使用Flask-Migrate数据库迁移框架可以保证数据库结构在发生变化时,改变数据库结构不至于丢失数据库的数据。
1. 安装
```
pip install Flask-Migrate
```
2. demo
```
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
```
3. 初始化
完成文件创建后就可以进行初始化了,切换到文件所在文件夹下,使用命令
```
flask db init
```
这个命令中的**db**是在*manager.py**migrate = Migrate(app, db)*这行代码中声明命令行对象名称;
init是Migrate命令,表示初始化迁移数据库,运行完成后会在当前目录下创建一个migrations文件夹,用于进行迁移的数据库脚本都放在这里。
4. 迁移数据库
可以实现数据库迁移仓库创建:
```
flask db migrate -m "Initial migration."
```
此时生成一个versions文件夹:
从数据库中能看到alembic_version表。
5. 更新数据库
```
flask db upgrade
```
6. 总结
+ 一是修改app部分代码,增加与Migrate相关的Command代码;
+ 二是准备好数据模型,即model.py文件中的内容;
+ 三是初始化和更新迁移数据库操作,即3次命令输入。
后面models目录下任何一个数据库表文件增加或者删除了字段,通过以下两步解决:
```
python manager.py db migrate
python manager.py db upgrade
```
详情参考:https://zhuanlan.zhihu.com/p/307612189
\ No newline at end of file
# -*- coding: utf-8 -*-
import string
import flask_restful
from flask import Flask, abort, jsonify
from flask_jwt_extended import ( JWTManager )
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from hashids import Hashids
from webcreator.response import ResponseCode, response_result
from webcreator.log import logger
from .config import config
# 初始化app
app = Flask(__name__)
# 初始化sqlalchemy
app.config.from_object(config)
db = SQLAlchemy(app)
# 初始化marshmallow
ma = Marshmallow(app)
# 增加jwt校验
jwt = JWTManager(app)
hash_ids = Hashids(salt='hvwptlmj027d5quf', min_length=8, alphabet=string.ascii_lowercase + string.digits) # hash函数
# 保留flask原生异常处理
handle_exception = app.handle_exception
handle_user_exception = app.handle_user_exception
# 过期令牌
@jwt.expired_token_loader
def expired_token_callback(jwt_header, jwt_payload):
logger.info(jwt_payload)
return jsonify({
'code': 4011,
'msg': 'token expired',
'data': jwt_header
})
# 无效令牌
@jwt.invalid_token_loader
def invalid_token_callback(error): # we have to keep the argument here, since it's passed in by the caller internally
return jsonify({
'code': 4012,
'msg': 'invalid token',
'data': error
})
# 校验失败
@jwt.unauthorized_loader
def unauthorized_callback(error):
return jsonify({
'code': 4013,
'msg': 'unauthorized',
'data': error
})
def _custom_abort(http_status_code, **kwargs):
"""
自定义abort 400响应数据格式
"""
if http_status_code == 400:
message = kwargs.get('message')
if isinstance(message, dict):
param, info = list(message.items())[0]
data = '{}:{}!'.format(param, info)
return abort(jsonify(response_result(ResponseCode.PARAMETER_ERROR, data=data)))
else:
return abort(jsonify(response_result(ResponseCode.PARAMETER_ERROR, data=message)))
# return { 'code': http_status_code, 'msg': kwargs.get('message') }
return abort(http_status_code)
def _access_control(response):
"""
解决跨域请求
"""
# response.headers['Access-Control-Allow-Origin'] = '*'
# response.headers['Access-Control-Allow-Methods'] = 'GET,HEAD,PUT,PATCH,POST,DELETE'
# response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
# response.headers['Access-Control-Max-Age'] = 86400
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, Authorization'
response.headers['Access-Control-Expose-Headers'] = 'Authorization'
response.headers['Access-Control-Max-Age'] = 86400
response.headers['Access-Control-Request-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
return response
def create_app(config):
"""
创建app
"""
# 添加配置
app.config.from_object(config)
# 解决跨域
app.after_request(_access_control)
# 自定义abort 400 响应数据格式
flask_restful.abort = _custom_abort
# 数据库初始化
db.init_app(app)
# 注册蓝图
from views import api_v1
app.register_blueprint(api_v1, url_prefix='/api/v1')
# 使用flask原生异常处理程序
app.handle_exception = handle_exception
app.handle_user_exception = handle_user_exception
return app
# -*- coding: utf-8 -*-
import os
import multiprocessing
MODE = 'develop' # develop: 开发模式; production: 生产模式
UPLOAD_ROOT_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'upload')
EXPORT_ROOT_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'export')
UPLOAD_ALLOWED = set(['doc', 'docs', 'csv', 'xls', 'xlsx'])
class ProductionConfig(object):
BIND = '127.0.0.1:3000'
WORKERS = multiprocessing.cpu_count() * 2 + 1
WORKER_CONNECTIONS = 10000
BACKLOG = 64
TIMEOUT = 60
LOG_LEVEL = 'INFO'
LOG_DIR_PATH = os.path.join(os.path.dirname(__file__), 'logs')
LOG_FILE_MAX_BYTES = 1024 * 1024 * 100
LOG_FILE_BACKUP_COUNT = 10
PID_FILE = 'run.pid'
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379
REDIS_PASSWORD = ''
REDIS_MAX_CONNECTIONS = 100
JWT_HEADER_NAME = 'Auth'
JWT_HEADER_TYPE = 'Bearer'
JWT_SECRET_KEY = '6UdxRgs2hvWpTLmj027d5vt7dXXQX'
JWT_ACCESS_TOKEN_EXPIRES = 7200
JWT_REFRESH_TOKEN_EXPIRES = 1800
MYSQL_DB = 'qianjing_iot'
MYSQL_HOST = '127.0.0.1'
MYSQL_PORT = 3306
MYSQL_USER = 'debian-sys-maint'
MYSQL_PWD = 'XMigC2B2uugnv18y'
SQLALCHEMY_BINDS = "sqlite:////test.db"
SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
def __init__(self):
super().__init__()
self.SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
class DevelopConfig(object):
BIND = '127.0.0.1:3000'
WORKERS = 2
WORKER_CONNECTIONS = 1000
BACKLOG = 64
TIMEOUT = 30
LOG_LEVEL = 'DEBUG'
LOG_DIR_PATH = os.path.join(os.path.dirname(__file__), 'logs')
LOG_FILE_MAX_BYTES = 1024 * 1024
LOG_FILE_BACKUP_COUNT = 1
PID_FILE = 'run.pid'
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379
REDIS_PASSWORD = ''
REDIS_MAX_CONNECTIONS = 100
JWT_HEADER_NAME = 'Auth'
JWT_HEADER_TYPE = 'Bearer'
JWT_SECRET_KEY = '6UdxRgs2hvWpTLmj027d5vt7dXXQX'
JWT_ACCESS_TOKEN_EXPIRES = 7200
JWT_REFRESH_TOKEN_EXPIRES = 1800
MYSQL_DB = 'qianjing_iot'
MYSQL_HOST = '127.0.0.1'
MYSQL_PORT = 3306
MYSQL_USER = 'debian-sys-maint'
MYSQL_PWD = 'XMigC2B2uugnv18y'
SQLALCHEMY_BINDS = "sqlite:////test.db"
SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_ECHO = False
def __init__(self):
super().__init__()
self.SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
if MODE == 'production':
config = ProductionConfig()
else:
config = DevelopConfig()
#!/usr/bin/env python
# -*- coding: utf_8 -*-
from webcreator.event import PySignal
class SignalManager(object):
actionPostArea = PySignal()
actionDeleteArea = PySignal()
actionGetListArea = PySignal()
actionGetArea = PySignal()
actionPutArea = PySignal()
actionPostApp = PySignal()
actionDeleteApp = PySignal()
actionGetListApp = PySignal()
actionGetApp = PySignal()
actionPutApp = PySignal()
actionGetListPackage = PySignal()
actionGetPackage = PySignal()
actionPostUser = PySignal()
actionDeleteUser = PySignal()
actionGetListUser = PySignal()
actionGetUser = PySignal()
actionPutUser = PySignal()
actionGetListLogin = PySignal()
actionGetLogin = PySignal()
def __init__(self):
super().__init__()
signalManager = SignalManager()
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf_8 -*-
from application.app import signalManager
from .area import areaManager
from .app import appManager
from .package import packageManager
from .user import userManager
from .login import loginManager
def initConnect():
signalManager.actionPostArea.connect(areaManager.post)
signalManager.actionDeleteArea.connect(areaManager.delete)
signalManager.actionGetListArea.connect(areaManager.getList)
signalManager.actionGetArea.connect(areaManager.get)
signalManager.actionPutArea.connect(areaManager.put)
signalManager.actionPostApp.connect(appManager.post)
signalManager.actionDeleteApp.connect(appManager.delete)
signalManager.actionGetListApp.connect(appManager.getList)
signalManager.actionGetApp.connect(appManager.get)
signalManager.actionPutApp.connect(appManager.put)
signalManager.actionGetListPackage.connect(packageManager.getList)
signalManager.actionGetPackage.connect(packageManager.get)
signalManager.actionPostUser.connect(userManager.post)
signalManager.actionDeleteUser.connect(userManager.delete)
signalManager.actionGetListUser.connect(userManager.getList)
signalManager.actionGetUser.connect(userManager.get)
signalManager.actionPutUser.connect(userManager.put)
signalManager.actionGetListLogin.connect(loginManager.getList)
signalManager.actionGetLogin.connect(loginManager.get)
initConnect()
\ No newline at end of file
from datetime import datetime
from application.app import db
from models.app import AppModel
from webcreator.utils import ResponseCode, response_result
class AppResource(object):
def __init__(self):
super().__init__()
def get(self, params):
# handle business
filters = []
result = AppModel.query.filter(*filters).order_by(AppModel.areaId).paginate(params.get('page', 1), params.get('pageSize', 10), error_out=False)
return result
def post(self, params, jwt=None):
# handle business
result = AppModel.query.filter(AppModel.areaName == params.get('areaName')).first()
if result and result.is_delete:
result.is_delete = False
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
return response_result(ResponseCode.OK)
elif result and result.is_delete == False:
return response_result(ResponseCode.EXISTS_ERROR)
result = AppModel(**params)
db.session.add(result)
db.session.commit()
return response_result(ResponseCode.OK)
def put(self, id, params, jwt=None):
# handle business
result = AppModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA)
if params:
for key, value in params.items():
if value != None: setattr(result, key, value)
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
else:
return response_result(ResponseCode.PARAM_NULL)
def delete(self, id, jwt=None):
# handle business
result = AppModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA_FOUND)
else:
result.update_by = jwt['id']
result.update_date = datetime.now()
result.is_delete = True
db.session.delete(result)
db.session.commit()
appManager = AppResource()
\ No newline at end of file
from datetime import datetime
from application.app import db
from models.area import AreaModel
from webcreator.utils import ResponseCode, response_result
class AreaResource(object):
def __init__(self):
super().__init__()
def get(self, params):
# handle business
filters = []
result = AreaModel.query.filter(*filters).order_by(AreaModel.areaId).paginate(params.get('page', 1), params.get('pageSize', 10), error_out=False)
return result
def post(self, params, jwt=None):
# handle business
result = AreaModel.query.filter(AreaModel.areaName == params.get('areaName')).first()
if result and result.is_delete:
result.is_delete = False
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
return response_result(ResponseCode.OK)
elif result and result.is_delete == False:
return response_result(ResponseCode.EXISTS_ERROR)
result = AreaModel(**params)
db.session.add(result)
db.session.commit()
return response_result(ResponseCode.OK)
def put(self, id, params, jwt=None):
# handle business
result = AreaModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA)
if params:
for key, value in params.items():
if value != None: setattr(result, key, value)
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
else:
return response_result(ResponseCode.PARAM_NULL)
def delete(self, id, jwt=None):
# handle business
result = AreaModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA_FOUND)
else:
result.update_by = jwt['id']
result.update_date = datetime.now()
result.is_delete = True
db.session.delete(result)
db.session.commit()
areaManager = AreaResource()
\ No newline at end of file
from datetime import datetime
from application.app import db
from models.login import LoginModel
from webcreator.utils import ResponseCode, response_result
class LoginResource(object):
def __init__(self):
super().__init__()
def get(self, params):
# handle business
filters = []
result = LoginModel.query.filter(*filters).order_by(LoginModel.areaId).paginate(params.get('page', 1), params.get('pageSize', 10), error_out=False)
return result
def post(self, params, jwt=None):
# handle business
result = LoginModel.query.filter(LoginModel.areaName == params.get('areaName')).first()
if result and result.is_delete:
result.is_delete = False
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
return response_result(ResponseCode.OK)
elif result and result.is_delete == False:
return response_result(ResponseCode.EXISTS_ERROR)
result = LoginModel(**params)
db.session.add(result)
db.session.commit()
return response_result(ResponseCode.OK)
def put(self, id, params, jwt=None):
# handle business
result = LoginModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA)
if params:
for key, value in params.items():
if value != None: setattr(result, key, value)
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
else:
return response_result(ResponseCode.PARAM_NULL)
def delete(self, id, jwt=None):
# handle business
result = LoginModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA_FOUND)
else:
result.update_by = jwt['id']
result.update_date = datetime.now()
result.is_delete = True
db.session.delete(result)
db.session.commit()
loginManager = LoginResource()
\ No newline at end of file
from datetime import datetime
from application.app import db
from models.package import PackageModel
from webcreator.utils import ResponseCode, response_result
class PackageResource(object):
def __init__(self):
super().__init__()
def get(self, params):
# handle business
filters = []
result = PackageModel.query.filter(*filters).order_by(PackageModel.areaId).paginate(params.get('page', 1), params.get('pageSize', 10), error_out=False)
return result
def post(self, params, jwt=None):
# handle business
result = PackageModel.query.filter(PackageModel.areaName == params.get('areaName')).first()
if result and result.is_delete:
result.is_delete = False
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
return response_result(ResponseCode.OK)
elif result and result.is_delete == False:
return response_result(ResponseCode.EXISTS_ERROR)
result = PackageModel(**params)
db.session.add(result)
db.session.commit()
return response_result(ResponseCode.OK)
def put(self, id, params, jwt=None):
# handle business
result = PackageModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA)
if params:
for key, value in params.items():
if value != None: setattr(result, key, value)
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
else:
return response_result(ResponseCode.PARAM_NULL)
def delete(self, id, jwt=None):
# handle business
result = PackageModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA_FOUND)
else:
result.update_by = jwt['id']
result.update_date = datetime.now()
result.is_delete = True
db.session.delete(result)
db.session.commit()
packageManager = PackageResource()
\ No newline at end of file
from datetime import datetime
from application.app import db
from models.user import UserModel
from webcreator.utils import ResponseCode, response_result
class UserResource(object):
def __init__(self):
super().__init__()
def get(self, params):
# handle business
filters = []
result = UserModel.query.filter(*filters).order_by(UserModel.areaId).paginate(params.get('page', 1), params.get('pageSize', 10), error_out=False)
return result
def post(self, params, jwt=None):
# handle business
result = UserModel.query.filter(UserModel.areaName == params.get('areaName')).first()
if result and result.is_delete:
result.is_delete = False
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
return response_result(ResponseCode.OK)
elif result and result.is_delete == False:
return response_result(ResponseCode.EXISTS_ERROR)
result = UserModel(**params)
db.session.add(result)
db.session.commit()
return response_result(ResponseCode.OK)
def put(self, id, params, jwt=None):
# handle business
result = UserModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA)
if params:
for key, value in params.items():
if value != None: setattr(result, key, value)
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
else:
return response_result(ResponseCode.PARAM_NULL)
def delete(self, id, jwt=None):
# handle business
result = UserModel.query.get(id)
if not result: return response_result(ResponseCode.NO_DATA_FOUND)
else:
result.update_by = jwt['id']
result.update_date = datetime.now()
result.is_delete = True
db.session.delete(result)
db.session.commit()
userManager = UserResource()
\ No newline at end of file
This diff is collapsed.
# -*- coding: utf-8 -*-
from gevent import monkey
monkey.patch_all()
import logging
from tornado.wsgi import WSGIContainer
from tornado.web import Application, FallbackHandler
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from flask_script import Manager
from flask_migrate import Migrate
from multiprocessing import cpu_count
from application.app import create_app, db
from application.config import config
# 根据配置初始化app
app = create_app(config)
migrate = Migrate(app, db)
manager = Manager(app)
@manager.command
def run():
"""
生产模式启动命令函数
To use: python3 manager.py run
"""
# app.logger.setLevel(app.config.get('LOG_LEVEL', logging.INFO))
# service_config = {
# 'bind': app.config.get('BIND', '0.0.0.0:3000'),
# 'workers': app.config.get('WORKERS', cpu_count() * 2 + 1),
# 'worker_class': 'gevent',
# 'worker_connections': app.config.get('WORKER_CONNECTIONS', 10000),
# 'backlog': app.config.get('BACKLOG', 2048),
# 'timeout': app.config.get('TIMEOUT', 60),
# 'loglevel': app.config.get('LOG_LEVEL', 'info'),
# 'pidfile': app.config.get('PID_FILE', 'run.pid'),
# }
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(3000, address='127.0.0.1')
# wsgi_app = WSGIContainer(app)
# application = Application([
# (r'.*', FallbackHandler, dict(fallback=wsgi_app))
# ], **service_config)
# application.listen(3000)
IOLoop.instance().start()
@manager.command
def debug():
"""
debug模式启动命令函数
To use: python3 manager.py debug
"""
# app.logger.setLevel(logging.DEBUG)
print("start from here......")
app.run(debug=True, port=3000, host='127.0.0.1')
if __name__ == '__main__':
manager.run()
# -*- coding: utf-8 -*-
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declared_attr, declarative_base
class BaseModelMixin(object):
@declared_attr
def __tablename__(self):
return self.__name__.lower()
# __table_args__ = {'mysql_engine': 'InnoDB'}
id = Column(Integer, primary_key=True)
BaseModel = declarative_base(cls=BaseModelMixin)
class MyMixin(object):
@declared_attr
def __tablename__(self):
return self.__name__.lower()
# __table_args__ = {'mysql_engine': 'InnoDB'}
__mapper_args__= {'always_refresh': True}
id = Column(Integer, primary_key=True)
# example:
class MyModel(MyMixin, BaseModel):
name = Column(String(1000))
# -*- coding: utf-8 -*-
from application.app import db, ma
from .base import PrimaryModel
from marshmallow import Schema, fields, INCLUDE, EXCLUDE
class AppModel(PrimaryModel):
__tablename__ = 'evm_app'
app_name = db.Column(db.String(70), index = True)
app_icon = db.Column(db.String(200))
app_version = db.Column(db.String(20))
category = db.Column(db.Integer)
category_2th = db.Column(db.Integer)
developer = db.Column(db.Integer)
download_url = db.Column(db.String(20))
app_file_size = db.Column(db.Integer)
app_screen_size = db.Column(db.Integer)
app_arch = db.Column(db.String(20))
app_review = db.Column(db.String(100))
# __table_args__ = (
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self, app_name, app_icon, app_version, category, category_2th, developer, download_url, app_file_size, app_screen_size, app_arch, app_review):
self.app_name = app_name
self.app_icon = app_icon
self.app_version = app_version
self.category = category
self.category_2th = category_2th
self.developer = developer
self.download_url = download_url
self.app_file_size = app_file_size
self.app_screen_size = app_screen_size
self.app_arch = app_arch
self.app_review = app_review
def __repr__(self):
return '<AppModel %r>' % (self.app_name)
def to_json(self):
return {
'app_name': self.app_name,
'app_icon': self.app_icon,
'app_version': self.app_version,
'category': self.category,
'category_2th': self.category_2th,
'developer': self.developer,
'download_url': self.download_url,
'app_file_size': self.app_file_size,
'app_screen_size': self.app_screen_size,
'app_arch': self.app_arch,
'app_review': self.app_review,
}
class PostAppSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AppModel
app_name = ma.auto_field()
app_icon = ma.auto_field()
app_version = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
developer = ma.auto_field()
app_screen_size = ma.auto_field()
app_arch = ma.auto_field()
app_review = ma.auto_field()
postAppSchema = PostAppSchema()
postAppsSchema = PostAppSchema(many=True)
class DeleteAppSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AppModel
deleteAppSchema = DeleteAppSchema()
class GetListAppSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AppModel
page = fields.Integer(required=False)
pageSize = fields.Integer(required=False)
app_name = ma.auto_field()
app_version = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
app_arch = ma.auto_field()
getListAppSchema = GetListAppSchema()
class GetAppSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AppModel
app_name = ma.auto_field()
app_version = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
app_arch = ma.auto_field()
getAppSchema = GetAppSchema()
class PutAppSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AppModel
app_name = ma.auto_field()
app_icon = ma.auto_field()
app_version = ma.auto_field()
app_screen_size = ma.auto_field()
app_arch = ma.auto_field()
app_review = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
putAppSchema = PutAppSchema()
# -*- coding: utf-8 -*-
from application.app import db, ma
from .base import PrimaryModel
from marshmallow import Schema, fields, INCLUDE, EXCLUDE
class AreaModel(PrimaryModel):
__tablename__ = 'evm_area'
areaCode = db.Column(db.String(20), index = True)
areaName = db.Column(db.String(20), index = True)
level = db.Column(db.Integer, default = 1)
cityCode = db.Column(db.Integer)
center = db.Column(db.String(20), index = True)
parentId = db.Column(db.String(20))
hasChildren = db.Column(db.Boolean)
# __table_args__ = (
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self, areaCode, areaName, level, cityCode, center, parentId, hasChildren):
self.areaCode = areaCode
self.areaName = areaName
self.level = level
self.cityCode = cityCode
self.center = center
self.parentId = parentId
self.hasChildren = hasChildren
def __repr__(self):
return '<AreaModel %r>' % (self.areaCode)
def to_json(self):
return {
'areaCode': self.areaCode,
'areaName': self.areaName,
'level': self.level,
'cityCode': self.cityCode,
'center': self.center,
'parentId': self.parentId,
'hasChildren': self.hasChildren,
}
class PostAreaSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AreaModel
areaCode = ma.auto_field()
areaName = ma.auto_field()
level = ma.auto_field()
cityCode = ma.auto_field()
center = ma.auto_field()
postAreaSchema = PostAreaSchema()
postAreasSchema = PostAreaSchema(many=True)
class DeleteAreaSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AreaModel
deleteAreaSchema = DeleteAreaSchema()
class GetListAreaSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AreaModel
page = fields.Integer(required=False)
pageSize = fields.Integer(required=False)
areaName = ma.auto_field()
level = ma.auto_field()
parentId = ma.auto_field()
hasChildren = ma.auto_field()
field = fields.String(required=False, length=None)
getListAreaSchema = GetListAreaSchema()
class GetAreaSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AreaModel
areaName = ma.auto_field()
level = ma.auto_field()
parentId = ma.auto_field()
hasChildren = ma.auto_field()
field = fields.String(required=False, length=None)
getAreaSchema = GetAreaSchema()
class PutAreaSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = AreaModel
areaName = ma.auto_field()
level = ma.auto_field()
parentId = ma.auto_field()
hasChildren = ma.auto_field()
field = fields.String(required=False, length=None)
putAreaSchema = PutAreaSchema()
# -*- coding: utf-8 -*-
import uuid
from datetime import datetime
from application.app import db
class BaseModel(db.Model):
# Flask-SQLAlchemy创建table时,如何声明基类(这个类不会创建表,可以被继承)
# 方法就是把__abstract__这个属性设置为True,这个类为基类,不会被创建为表!
__abstract__ = True
create_at = db.Column(db.DateTime, default=datetime.now)
create_by = db.Column(db.String(64))
update_at = db.Column(db.DateTime, default=datetime.now)
update_by = db.Column(db.String(64))
remarks = db.Column(db.String(255), default="")
is_delete = db.Column(db.BOOLEAN, default=0)
class PrimaryModel(BaseModel):
__abstract__ = True
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
uuid = db.Column(db.String(64), primary_key=True, default=uuid.uuid1)
class AutoBaseModel(BaseModel):
__abstract__ = True
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
sort = db.Column(db.Integer, default=0)
class UuidBaseModel(BaseModel):
__abstract__ = True
id = db.Column(db.String(64), primary_key=True, default=uuid.uuid1)
sort = db.Column(db.Integer, default=0)
class SortBaseModel(BaseModel):
__abstract__ = True
sort = db.Column(db.Integer, default=0)
\ No newline at end of file
# -*- coding: utf-8 -*-
from application.app import db, ma
from .base import PrimaryModel
from marshmallow import Schema, fields, INCLUDE, EXCLUDE
class LoginModel(PrimaryModel):
__tablename__ = 'evm_login'
user = db.Column(db.Integer)
login_at = db.Column(db.String(200))
user_agent = db.Column(db.String(200))
ip = db.Column(db.String(128))
geo_location = db.Column(db.String(200))
operator = db.Column(db.String(50))
# __table_args__ = (
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self, user, login_at, user_agent, ip, geo_location, operator):
self.user = user
self.login_at = login_at
self.user_agent = user_agent
self.ip = ip
self.geo_location = geo_location
self.operator = operator
def __repr__(self):
return '<LoginModel %r>' % (self.user)
def to_json(self):
return {
'login_at': self.login_at,
'user_agent': self.user_agent,
'ip': self.ip,
'geo_location': self.geo_location,
'operator': self.operator,
}
class GetListLoginSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = LoginModel
page = fields.Integer(required=False)
pageSize = fields.Integer(required=False)
user = ma.auto_field()
login_at = ma.auto_field()
user_agent = ma.auto_field()
ip = ma.auto_field()
geo_location = ma.auto_field()
operator = ma.auto_field()
getListLoginSchema = GetListLoginSchema()
class GetLoginSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = LoginModel
user = ma.auto_field()
login_at = ma.auto_field()
user_agent = ma.auto_field()
ip = ma.auto_field()
geo_location = ma.auto_field()
operator = ma.auto_field()
getLoginSchema = GetLoginSchema()
# -*- coding: utf-8 -*-
from application.app import db, ma
from .base import PrimaryModel
from marshmallow import Schema, fields, INCLUDE, EXCLUDE
class PackageModel(PrimaryModel):
__tablename__ = 'evm_package'
app = db.Column(db.Integer)
app_version = db.Column(db.String(200))
package_info = db.Column(db.String(20))
file_path = db.Column(db.String(200))
source = db.Column(db.Integer)
user_agent = db.Column(db.String(200))
download_url = db.Column(db.String(200))
ip = db.Column(db.String(128))
geo_location = db.Column(db.String(200))
operator = db.Column(db.String(50))
# __table_args__ = (
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self, app, app_version, package_info, file_path, source, user_agent, download_url, ip, geo_location, operator):
self.app = app
self.app_version = app_version
self.package_info = package_info
self.file_path = file_path
self.source = source
self.user_agent = user_agent
self.download_url = download_url
self.ip = ip
self.geo_location = geo_location
self.operator = operator
def __repr__(self):
return '<PackageModel %r>' % (self.app)
def to_json(self):
return {
'app_version': self.app_version,
'package_info': self.package_info,
'file_path': self.file_path,
'source': self.source,
'user_agent': self.user_agent,
'download_url': self.download_url,
'ip': self.ip,
'geo_location': self.geo_location,
'operator': self.operator,
}
class GetListPackageSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = PackageModel
page = fields.Integer(required=False)
pageSize = fields.Integer(required=False)
app = ma.auto_field()
app_version = ma.auto_field()
package_info = ma.auto_field()
file_path = ma.auto_field()
source = ma.auto_field()
user_agent = ma.auto_field()
download_url = ma.auto_field()
ip = ma.auto_field()
geo_location = ma.auto_field()
operator = ma.auto_field()
getListPackageSchema = GetListPackageSchema()
class GetPackageSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = PackageModel
app = ma.auto_field()
app_version = ma.auto_field()
package_info = ma.auto_field()
file_path = ma.auto_field()
source = ma.auto_field()
user_agent = ma.auto_field()
download_url = ma.auto_field()
ip = ma.auto_field()
geo_location = ma.auto_field()
operator = ma.auto_field()
getPackageSchema = GetPackageSchema()
# -*- coding: utf-8 -*-
from application.app import db, ma
from .base import PrimaryModel
from marshmallow import Schema, fields, INCLUDE, EXCLUDE
class UserModel(PrimaryModel):
__tablename__ = 'evm_user'
app_name = db.Column(db.String(70), index = True)
app_icon = db.Column(db.String(200))
app_version = db.Column(db.String(20))
category = db.Column(db.Integer)
category_2th = db.Column(db.Integer)
developer = db.Column(db.Integer)
download_url = db.Column(db.String(20))
app_file_size = db.Column(db.Integer)
app_screen_size = db.Column(db.Integer)
app_arch = db.Column(db.String(20))
app_review = db.Column(db.String(100))
# __table_args__ = (
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self, app_name, app_icon, app_version, category, category_2th, developer, download_url, app_file_size, app_screen_size, app_arch, app_review):
self.app_name = app_name
self.app_icon = app_icon
self.app_version = app_version
self.category = category
self.category_2th = category_2th
self.developer = developer
self.download_url = download_url
self.app_file_size = app_file_size
self.app_screen_size = app_screen_size
self.app_arch = app_arch
self.app_review = app_review
def __repr__(self):
return '<UserModel %r>' % (self.app_name)
def to_json(self):
return {
'app_name': self.app_name,
'app_icon': self.app_icon,
'app_version': self.app_version,
'category': self.category,
'category_2th': self.category_2th,
'developer': self.developer,
'download_url': self.download_url,
'app_file_size': self.app_file_size,
'app_screen_size': self.app_screen_size,
'app_arch': self.app_arch,
'app_review': self.app_review,
}
class PostUserSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = UserModel
app_name = ma.auto_field()
app_icon = ma.auto_field()
app_version = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
developer = ma.auto_field()
app_screen_size = ma.auto_field()
app_arch = ma.auto_field()
app_review = ma.auto_field()
postUserSchema = PostUserSchema()
postUsersSchema = PostUserSchema(many=True)
class DeleteUserSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = UserModel
deleteUserSchema = DeleteUserSchema()
class GetListUserSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = UserModel
page = fields.Integer(required=False)
pageSize = fields.Integer(required=False)
app_name = ma.auto_field()
app_version = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
app_arch = ma.auto_field()
getListUserSchema = GetListUserSchema()
class GetUserSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = UserModel
app_name = ma.auto_field()
app_version = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
app_arch = ma.auto_field()
getUserSchema = GetUserSchema()
class PutUserSchema(ma.SQLAlchemySchema):
class Meta:
# unknown = INCLUDE # 未知字段默认包含
# unknown = EXCLUDE # 未知字段默认排除
model = UserModel
app_name = ma.auto_field()
app_icon = ma.auto_field()
app_version = ma.auto_field()
app_screen_size = ma.auto_field()
app_arch = ma.auto_field()
app_review = ma.auto_field()
category = ma.auto_field()
category_2th = ma.auto_field()
putUserSchema = PutUserSchema()
alembic==1.6.5
aniso8601==9.0.1
appdirs==1.4.4
asgiref==3.3.4
cffi==1.14.5
click==8.0.1
colorama==0.4.4
Flask==2.0.1
Flask-JWT-Extended==4.2.1
flask-marshmallow==0.14.0
Flask-Migrate==3.0.1
Flask-RESTful==0.3.9
Flask-Script==2.0.6
Flask-SQLAlchemy==2.5.1
fs==2.4.13
gevent==21.1.2
greenlet==1.1.0
gunicorn==20.1.0
h11==0.12.0
hashids==1.3.1
itsdangerous==2.0.1
Jinja2==3.0.1
Mako==1.1.4
MarkupSafe==2.0.1
marshmallow==3.12.1
marshmallow-sqlalchemy==0.26.1
pycparser==2.20
PyJWT==2.1.0
python-dateutil==2.8.1
python-editor==1.0.4
pytz==2021.1
six==1.16.0
SQLAlchemy==1.4.17
tornado==6.1
uvicorn==0.14.0
Werkzeug==2.0.1
zope.event==4.5.0
zope.interface==5.4.0
# -*- coding: utf-8 -*-
from flask import Blueprint
from flask_restful import Api
from . import area
from . import app
from . import package
from . import user
from . import login
api_v1 = Blueprint('api_v1', __name__)
api = Api(api_v1)
api.add_resource(area.AreaResource, '/area/<string:uuid>')
api.add_resource(area.AreaResourceList, '/area')
api.add_resource(app.AppResource, '/app/<string:uuid>')
api.add_resource(app.AppResourceList, '/app')
api.add_resource(package.PackageResource, '/package/<string:uuid>')
api.add_resource(package.PackageResourceList, '/package')
api.add_resource(user.UserResource, '/user/<string:uuid>')
api.add_resource(user.UserResourceList, '/user')
api.add_resource(login.LoginResource, '/login/<string:uuid>')
api.add_resource(login.LoginResourceList, '/login')
from flask import current_app, jsonify, request
from flask_restful import Resource
from flask_restful.reqparse import RequestParser
from flask_jwt_extended import ( jwt_required, get_jwt_identity )
from application.signal_manager import signalManager
from models.app import postAppSchema,deleteAppSchema,getListAppSchema,getAppSchema,putAppSchema
from webcreator.response import ResponseCode, response_result
class AppResource(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getListAppSchema.load(json_payload)
result = signalManager.actionGetApp.emit(**data)
json_dumps = getListAppSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def post(self):
try:
json_payload = request.json
data = postAppSchema.load(json_payload)
result = signalManager.actionPostApp.emit(**data)
json_dumps = postAppSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
class AppResourceList(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
@jwt_required
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getAppSchema.load(json_payload)
result = signalManager.actionGetApp.emit(**data)
json_dumps = getAppSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def put(self):
try:
json_payload = request.json
data = putAppSchema.load(json_payload)
result = signalManager.actionPutApp.emit(**data)
json_dumps = putAppSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def delete(self):
try:
json_payload = request.json
data = deleteAppSchema.load(json_payload)
result = signalManager.actionDeleteApp.emit(**data)
json_dumps = deleteAppSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
from flask import current_app, jsonify, request
from flask_restful import Resource
from flask_restful.reqparse import RequestParser
from flask_jwt_extended import ( jwt_required, get_jwt_identity )
from application.signal_manager import signalManager
from models.area import postAreaSchema,deleteAreaSchema,getListAreaSchema,getAreaSchema,putAreaSchema
from webcreator.response import ResponseCode, response_result
class AreaResource(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getListAreaSchema.load(json_payload)
result = signalManager.actionGetArea.emit(**data)
json_dumps = getListAreaSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def post(self):
try:
json_payload = request.json
data = postAreaSchema.load(json_payload)
result = signalManager.actionPostArea.emit(**data)
json_dumps = postAreaSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
class AreaResourceList(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
@jwt_required
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getAreaSchema.load(json_payload)
result = signalManager.actionGetArea.emit(**data)
json_dumps = getAreaSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def put(self):
try:
json_payload = request.json
data = putAreaSchema.load(json_payload)
result = signalManager.actionPutArea.emit(**data)
json_dumps = putAreaSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def delete(self):
try:
json_payload = request.json
data = deleteAreaSchema.load(json_payload)
result = signalManager.actionDeleteArea.emit(**data)
json_dumps = deleteAreaSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
from flask import current_app, jsonify, request
from flask_restful import Resource
from flask_restful.reqparse import RequestParser
from flask_jwt_extended import ( jwt_required, get_jwt_identity )
from application.signal_manager import signalManager
from models.login import getListLoginSchema,getLoginSchema
from webcreator.response import ResponseCode, response_result
class LoginResource(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getListLoginSchema.load(json_payload)
result = signalManager.actionGetLogin.emit(**data)
json_dumps = getListLoginSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
class LoginResourceList(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
@jwt_required
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getLoginSchema.load(json_payload)
result = signalManager.actionGetLogin.emit(**data)
json_dumps = getLoginSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
from flask import current_app, jsonify, request
from flask_restful import Resource
from flask_restful.reqparse import RequestParser
from flask_jwt_extended import ( jwt_required, get_jwt_identity )
from application.signal_manager import signalManager
from models.package import getListPackageSchema,getPackageSchema
from webcreator.response import ResponseCode, response_result
class PackageResource(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getListPackageSchema.load(json_payload)
result = signalManager.actionGetPackage.emit(**data)
json_dumps = getListPackageSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
class PackageResourceList(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
@jwt_required
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getPackageSchema.load(json_payload)
result = signalManager.actionGetPackage.emit(**data)
json_dumps = getPackageSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
from flask import current_app, jsonify, request
from flask_restful import Resource
from flask_restful.reqparse import RequestParser
from flask_jwt_extended import ( jwt_required, get_jwt_identity )
from application.signal_manager import signalManager
from models.user import postUserSchema,deleteUserSchema,getListUserSchema,getUserSchema,putUserSchema
from webcreator.response import ResponseCode, response_result
class UserResource(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getListUserSchema.load(json_payload)
result = signalManager.actionGetUser.emit(**data)
json_dumps = getListUserSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def post(self):
try:
json_payload = request.json
data = postUserSchema.load(json_payload)
result = signalManager.actionPostUser.emit(**data)
json_dumps = postUserSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
class UserResourceList(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
@jwt_required
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser.add_argument("page", type=int, location="args", default=1)
# self.parser.add_argument("pageSize", type=int, location="args", default=15)
# args = self.parser.parse_args()
try:
json_payload = request.json
print("========>", json_payload)
data = getUserSchema.load(json_payload)
result = signalManager.actionGetUser.emit(**data)
json_dumps = getUserSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def put(self):
try:
json_payload = request.json
data = putUserSchema.load(json_payload)
result = signalManager.actionPutUser.emit(**data)
json_dumps = putUserSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
@jwt_required
def delete(self):
try:
json_payload = request.json
data = deleteUserSchema.load(json_payload)
result = signalManager.actionDeleteUser.emit(**data)
json_dumps = deleteUserSchema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
# -*- coding: utf_8 -*-
\ No newline at end of file
# -*- coding: utf_8 -*-
############################
# Log
# 日志
############################
import os
import logging
from logging.handlers import RotatingFileHandler
logPath = os.getcwd() + os.path.sep + "logs"
if not os.path.exists(logPath):
os.makedirs(logPath)
fh = RotatingFileHandler("logs/running.log", maxBytes=10 * 1024 * 1024, backupCount=100)
fh.setLevel(logging.DEBUG)
# log write in console
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING)
# log formatter
formatter = logging.Formatter('[%(asctime)s][%(levelname)7s] [%(filename)15s%(funcName)15s%(lineno)06s] %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger = logging.root
logger.setLevel(logging.INFO)
logger.addHandler(fh)
logger.addHandler(ch)
\ No newline at end of file
# -*- coding: utf_8 -*-
############################
# Response
# 响应
############################
class ResponseCode(object):
OK = (200, 'ok')
NO_DATA = (204, 'no data')
NOT_FOUND = (404, 'not found')
NOTHING_CHANGE = (304, 'nothing change')
REQUEST_ERROR = (400, 'request error')
AUTHORIZATION_ERROR = (401, 'authentication error')
INVAILD_REQUEST = (403, 'invaild request')
PARAMETER_ERROR = (4001, 'parameter error')
PARAMETER_NULL = (4002, 'parameter is null')
PASSWORD_ERROR = (4003, 'password error')
EXISTS_ERROR = (4004, 'record exists')
INVAILD_ROLE_ERROR = (4005, 'invaild role error')
ACCOUNT_DISABLED = (4006, 'account is disabled')
SERVER_ERROR = (500, 'server error')
DB_ERROR = (5001, 'database error')
UNKNOWN_ERROR = (5003, 'unknown error')
def response_result(code, msg=None, data=None, **kwargs):
if msg is None:
msg = code[1]
result = { 'code': code[0], 'msg': msg, 'data': data }
result.update(kwargs)
return result
\ No newline at end of file
# -*- coding: utf-8 -*-
from typing import (
Any,
Optional,
Dict,
Mapping,
List,
Tuple,
Match,
Callable,
Type,
Sequence,
)
class Klass:
def __init__(self):
pass
......@@ -10,6 +23,18 @@ def dict2obj(dictionary):
klass.__dict__.update(dictionary)
return klass
class ObjectDict(Dict[str, Any]):
"""Makes a dictionary behave like an object, with attribute-style access."""
def __getattr__(self, name: str) -> Any:
try:
return self[name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name: str, value: Any) -> None:
self[name] = value
if __name__ == "__main__":
d = { 'a': 1, 'b': 2 }
print(dict2obj(d))
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf_8 -*-
import websocket
from flask import json
from tornado.websocket import WebSocketHandler, WebSocketClosedError
from utils import ObjectDict
from .log import logger
class WebsocketResponse(ObjectDict):
def __init__(self, type="Response", api_code=-1, message='fail', data=None, traceback=""):
super(WebsocketResponse, self).__init__()
self.type = type
self.code = api_code
self.message = message
self.data = data
self.traceback = traceback
if isinstance(self.data, list):
self.count = len(self.data)
def pushmessage(func):
def send(*agrs, **kwargs):
self = agrs[0]
ret = func(*agrs, **kwargs)
if ret:
msg, binary = ret
try:
if isinstance(msg, WebsocketResponse) or isinstance(msg, dict):
self.write_message(json.dumps(msg), binary)
elif isinstance(msg, str) or isinstance(msg, str):
self.write_message(msg, binary)
else:
self.write_message(repr(msg), binary)
except WebSocketClosedError as e:
logger.error(e)
self.on_close()
return send
class BaseWebsocket(WebSocketHandler):
handlers = {}
def open(self):
logger.warn("websocket of %s is opened", repr(self))
className = self.__class__.__name__
if className not in self.handlers:
self.handlers[className] = set()
self.handlers[className].add(self)
@pushmessage
def send(self, message, binary=False):
return message, binary
def on_close(self):
logger.warn("websocket of %s is closed", repr(self))
className = self.__class__.__name__
if className in self.handlers:
self.handlers[className].remove(self)
def check_origin(self, origin):
return True
@classmethod
def boardcastMessage(cls, message, binary=False):
className = cls.__name__
if className in cls.handlers:
for handler in cls.handlers[className]:
handler.send(message, binary)
class NotifyHandler(BaseWebsocket):
"""
建立与web前端的通信连接,发送状态信息报文
"""
def open(self):
super(NotifyHandler, self).open()
def on_message(self, message):
pass
class ThreadNotifyHandler(BaseWebsocket):
"""
建立与tornado主线程与子线程之间的通信连接
"""
def open(self):
super(ThreadNotifyHandler, self).open()
def on_message(self, message):
NotifyHandler.boardcastMessage(message)
class Wsclient(object):
"""
用于和ThreadNotifyHandler建立websocket连接的客户端
使用方式:在子线程中建立到达threadnotify路由的websocket客户端如
wsclient = Wsclient()
wsclient.send(WebsocketResponse("dashboard", 0, "success", data=cache))
"""
def __init__(self):
super(Wsclient, self).__init__()
self.wsclient = websocket.WebSocket()
self.wsclient.connect("ws://localhost:7777/ws/api/v1/threadnotify")
def send(self, msg):
if isinstance(msg, dict):
msg = json.dumps(msg)
self.wsclient.send(msg)
This diff is collapsed.
{
"application": {
"name": "evm-store",
"host": "127.0.0.1",
"port": 1000,
"jwtSecret": "",
"tablePrefix": "evm_",
"logLevel": "debug",
"mysql": {
"host": "127.0.0.1",
"port": 3306,
"username": "root",
"password": "admin",
"database": "app"
},
"sqlite": {
"file": "xxx.db"
}
},
"apis": [
{
"name": "area",
"contronller": {
"className": "AreaResource"
},
"model": {
"className": "AreaModel",
"tableName": "area",
"fields": [
{
"name": "areaId",
"dataType": "Integer",
"primaryKey": true,
"autoIncrement": true
},
{
"name": "areaCode",
"dataType": "String",
"default": "",
"length": 20,
"index": true,
"required": true
},
{
"name": "areaName",
"dataType": "String",
"default": "",
"length": 20,
"index": true,
"required": true
},
{
"name": "level",
"dataType": "Integer",
"default": 1,
"length": 20,
"required": true
},
{
"name": "cityCode",
"dataType": "Integer",
"default": ""
},
{
"name": " center",
"dataType": "String",
"default": "",
"length": 20,
"index": true,
"required": true
},
{
"name": "parentId",
"dataType": "String",
"default": "",
"length": 20,
"index": false,
"required": true
},
{
"name": "hasChildren",
"dataType": "Boolean",
"default": false
}
]
},
"view": {
"post": {
"auth": true,
"path": "/test/<string:id>",
"endpoint": "",
"params": [
{
"name": "areaCode",
"dataType": "str",
"location": "json",
"default": "",
"required": false
},
{
"name": "areaName",
"dataType": "str",
"location": "json",
"default": "",
"required": false
},
{
"name": "level",
"dataType": "int",
"location": "",
"default": "",
"required": false
},
{
"name": "cityCode",
"detaType": "str",
"location": "",
"default": "",
"required": false
},
{
"name": "center",
"dataType": "str",
"location": "",
"default": "",
"required": false
}
]
},
"delete": {
"auth": true,
"path": "/test/<string:id>",
"endpoint": "",
"params": []
},
"get": {
"auth": true,
"path": "",
"endpoint": "",
"params": [
{
"name": "pageNum",
"dataType": "int",
"location": "args",
"default": 1,
"required": false
},
{
"name": "pageSize",
"dataType": "int",
"location": "args",
"default": 10,
"required": false
},
{
"name": "areaName",
"dataType": "str",
"location": "args",
"default": null,
"required": false
},
{
"name": "level",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "parentId",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "hasChildren",
"dataType": "bool",
"location": "args",
"default": null,
"required": false
},
{
"name": "field",
"dataType": "str",
"location": "args",
"default": null,
"required": false
}
]
},
"put": {
"auth": true,
"path": "",
"endpoint": "",
"params": [
{
"name": "areaName",
"dataType": "str",
"location": "args",
"default": null,
"required": false
},
{
"name": "level",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "parentId",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "hasChildren",
"dataType": "bool",
"location": "args",
"default": null,
"required": false
},
{
"name": "field",
"dataType": "str",
"location": "args",
"default": null,
"required": false
}
]
}
}
}
]
}
\ No newline at end of file
from fs.copy import copy_fs
from jinja2 import Environment, FileSystemLoader
import json
import os
import re
def handleResources():
pass
'''
流程:
一、将resources里面所有文件夹拷贝到当前目录下
二、解析json配置文件,遍历每一项生成/model/view/controller
三、自动运行项目
'''
def handleController():
# 根据模型字段自动从models列表中取出file name信息和class name信息
pass
# 将字符串首字母转换成大写字母
def convertFirstLetterUpper(text_str):
# return text_str.capitalize()
# print("////////////////////>>>>", text_str)
return re.sub("([a-zA-Z])", lambda x: x.groups()[0].upper(), text_str, 1)
# ROOT = os.path.abspath(os.getcwd())
jinja_env = Environment(loader=FileSystemLoader(os.path.join(os.getcwd(), 'templates')))
jinja_env.filters['letterUpper'] = convertFirstLetterUpper
input_dir = None
output_dir = None
def copyFiles(src_dir, dst_dir):
copy_fs(src_dir, dst_dir)
def handleResources(config):
# 处理路由页面
# 遍历config文件,收集所有的action和name,action和name的首字母必须大写
# 然后才生成路由配置页面
target_file = os.sep.join(["views", "__init__.py"])
handleRender(config, 'router.tpl', target_file)
def handleModel():
def handleSignal(config):
# 生成信号槽模块
target_file = os.sep.join(["application", "signal_manager.py"])
handleRender(config, 'signal_manager.tpl', target_file)
target_file = os.sep.join(["controllers", "__init__.py"])
handleRender(config, 'signal_manager_init.tpl', target_file)
def handleModel(config, application):
# 将所有有默认值的字段分为一组,没有默认值的字段分为另一组
# 生成模板代码时,无默认值的字段在前,有默认值的字段字在后
pass
# 收集表字段信息
fields = []
extend = False
for m in config.get("model").get("fields"):
fields.append(m.get("name"))
extend = True
print(m)
target_file = os.sep.join(["models", "{}.py".format(config.get("name"))])
handleRender(config, 'model.tpl', target_file, fields=fields, extend=extend, application=application)
def hanleRender():
pass
def handleView(config):
target_file = os.sep.join(["views", "{}.py".format(config.get("name"))])
handleRender(config, 'view.tpl', target_file)
def handleController(config):
# 根据模型字段自动从models列表中取出file name信息和class name信息
target_file = os.sep.join(["controllers", "{}.py".format(config.get("name"))])
handleRender(config, 'controller.tpl', target_file)
def handleRender(result, tpl, target_file, **kwargs):
global output_dir
# print("=========>", result.get("name"), "{}.py".format(result.get("name")))
jinja_tpl = jinja_env.get_template(tpl)
content = jinja_tpl.render({ "config": result, **kwargs })
# print("############", output_dir)
target_file = os.sep.join([output_dir, target_file])
if not os.path.exists(os.path.dirname(target_file)):
os.makedirs(os.path.dirname(target_file))
with open(target_file, 'w', encoding='utf-8') as f:
f.write(content)
def parseConfig(config):
# 解析配置文件
for cfg in config.get("apis"):
handleModel(cfg, config.get("application"))
handleView(cfg)
handleController(cfg)
handleResources(config.get("apis"))
handleSignal(config.get("apis"))
def readConfig():
result = {}
......@@ -21,6 +92,16 @@ def readConfig():
result = json.loads(f.read())
return result
def run():
global input_dir
global output_dir
input_dir = os.sep.join([os.getcwd(), "resources"])
output_dir = os.sep.join([os.getcwd(), "build_out"])
copyFiles(input_dir, output_dir)
config = readConfig()
# print(config)
parseConfig(config)
print("success ......")
if __name__ == "__main__":
result = readConfig()
print(result)
\ No newline at end of file
run()
\ No newline at end of file
Jinja2==2.11.3
MarkupSafe==1.1.1
# Flask-Migrate
数据库迁移工具:使用Flask-Migrate数据库迁移框架可以保证数据库结构在发生变化时,改变数据库结构不至于丢失数据库的数据。
1. 安装
```
pip install Flask-Migrate
```
2. demo
```
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
```
3. 初始化
完成文件创建后就可以进行初始化了,切换到文件所在文件夹下,使用命令
```
flask db init
```
这个命令中的**db**是在*manager.py**migrate = Migrate(app, db)*这行代码中声明命令行对象名称;
init是Migrate命令,表示初始化迁移数据库,运行完成后会在当前目录下创建一个migrations文件夹,用于进行迁移的数据库脚本都放在这里。
4. 迁移数据库
可以实现数据库迁移仓库创建:
```
flask db migrate -m "Initial migration."
```
此时生成一个versions文件夹:
从数据库中能看到alembic_version表。
5. 更新数据库
```
flask db upgrade
```
6. 总结
+ 一是修改app部分代码,增加与Migrate相关的Command代码;
+ 二是准备好数据模型,即model.py文件中的内容;
+ 三是初始化和更新迁移数据库操作,即3次命令输入。
后面models目录下任何一个数据库表文件增加或者删除了字段,通过以下两步解决:
```
python manager.py db migrate
python manager.py db upgrade
```
详情参考:https://zhuanlan.zhihu.com/p/307612189
\ No newline at end of file
# -*- coding: utf-8 -*-
import string
import flask_restful
from flask import Flask, abort, jsonify
from flask_jwt_extended import ( JWTManager )
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from hashids import Hashids
from webcreator.response import ResponseCode, response_result
from webcreator.log import logger
from .config import config
# 初始化app
app = Flask(__name__)
# 初始化sqlalchemy
app.config.from_object(config)
db = SQLAlchemy(app)
# 初始化marshmallow
ma = Marshmallow(app)
# 增加jwt校验
jwt = JWTManager(app)
hash_ids = Hashids(salt='hvwptlmj027d5quf', min_length=8, alphabet=string.ascii_lowercase + string.digits) # hash函数
# 保留flask原生异常处理
handle_exception = app.handle_exception
handle_user_exception = app.handle_user_exception
# 过期令牌
@jwt.expired_token_loader
def expired_token_callback(jwt_header, jwt_payload):
logger.info(jwt_payload)
return jsonify({
'code': 4011,
'msg': 'token expired',
'data': jwt_header
})
# 无效令牌
@jwt.invalid_token_loader
def invalid_token_callback(error): # we have to keep the argument here, since it's passed in by the caller internally
return jsonify({
'code': 4012,
'msg': 'invalid token',
'data': error
})
# 校验失败
@jwt.unauthorized_loader
def unauthorized_callback(error):
return jsonify({
'code': 4013,
'msg': 'unauthorized',
'data': error
})
def _custom_abort(http_status_code, **kwargs):
"""
自定义abort 400响应数据格式
"""
if http_status_code == 400:
message = kwargs.get('message')
if isinstance(message, dict):
param, info = list(message.items())[0]
data = '{}:{}!'.format(param, info)
return abort(jsonify(response_result(ResponseCode.PARAMETER_ERROR, data=data)))
else:
return abort(jsonify(response_result(ResponseCode.PARAMETER_ERROR, data=message)))
# return { 'code': http_status_code, 'msg': kwargs.get('message') }
return abort(http_status_code)
def _access_control(response):
"""
解决跨域请求
"""
# response.headers['Access-Control-Allow-Origin'] = '*'
# response.headers['Access-Control-Allow-Methods'] = 'GET,HEAD,PUT,PATCH,POST,DELETE'
# response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
# response.headers['Access-Control-Max-Age'] = 86400
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, Authorization'
response.headers['Access-Control-Expose-Headers'] = 'Authorization'
response.headers['Access-Control-Max-Age'] = 86400
response.headers['Access-Control-Request-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
return response
def create_app(config):
"""
创建app
"""
# 添加配置
app.config.from_object(config)
# 解决跨域
app.after_request(_access_control)
# 自定义abort 400 响应数据格式
flask_restful.abort = _custom_abort
# 数据库初始化
db.init_app(app)
# 注册蓝图
from views import api_v1
app.register_blueprint(api_v1, url_prefix='/api/v1')
# 使用flask原生异常处理程序
app.handle_exception = handle_exception
app.handle_user_exception = handle_user_exception
return app
# -*- coding: utf-8 -*-
import os
import multiprocessing
MODE = 'develop' # develop: 开发模式; production: 生产模式
UPLOAD_ROOT_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'upload')
EXPORT_ROOT_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'export')
UPLOAD_ALLOWED = set(['doc', 'docs', 'csv', 'xls', 'xlsx'])
class ProductionConfig(object):
BIND = '127.0.0.1:3000'
WORKERS = multiprocessing.cpu_count() * 2 + 1
WORKER_CONNECTIONS = 10000
BACKLOG = 64
TIMEOUT = 60
LOG_LEVEL = 'INFO'
LOG_DIR_PATH = os.path.join(os.path.dirname(__file__), 'logs')
LOG_FILE_MAX_BYTES = 1024 * 1024 * 100
LOG_FILE_BACKUP_COUNT = 10
PID_FILE = 'run.pid'
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379
REDIS_PASSWORD = ''
REDIS_MAX_CONNECTIONS = 100
JWT_HEADER_NAME = 'Auth'
JWT_HEADER_TYPE = 'Bearer'
JWT_SECRET_KEY = '6UdxRgs2hvWpTLmj027d5vt7dXXQX'
JWT_ACCESS_TOKEN_EXPIRES = 7200
JWT_REFRESH_TOKEN_EXPIRES = 1800
MYSQL_DB = 'qianjing_iot'
MYSQL_HOST = '127.0.0.1'
MYSQL_PORT = 3306
MYSQL_USER = 'debian-sys-maint'
MYSQL_PWD = 'XMigC2B2uugnv18y'
SQLALCHEMY_BINDS = "sqlite:////test.db"
SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
def __init__(self):
super().__init__()
self.SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
class DevelopConfig(object):
BIND = '127.0.0.1:3000'
WORKERS = 2
WORKER_CONNECTIONS = 1000
BACKLOG = 64
TIMEOUT = 30
LOG_LEVEL = 'DEBUG'
LOG_DIR_PATH = os.path.join(os.path.dirname(__file__), 'logs')
LOG_FILE_MAX_BYTES = 1024 * 1024
LOG_FILE_BACKUP_COUNT = 1
PID_FILE = 'run.pid'
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379
REDIS_PASSWORD = ''
REDIS_MAX_CONNECTIONS = 100
JWT_HEADER_NAME = 'Auth'
JWT_HEADER_TYPE = 'Bearer'
JWT_SECRET_KEY = '6UdxRgs2hvWpTLmj027d5vt7dXXQX'
JWT_ACCESS_TOKEN_EXPIRES = 7200
JWT_REFRESH_TOKEN_EXPIRES = 1800
MYSQL_DB = 'qianjing_iot'
MYSQL_HOST = '127.0.0.1'
MYSQL_PORT = 3306
MYSQL_USER = 'debian-sys-maint'
MYSQL_PWD = 'XMigC2B2uugnv18y'
SQLALCHEMY_BINDS = "sqlite:////test.db"
SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_ECHO = False
def __init__(self):
super().__init__()
self.SQLALCHEMY_DATABASE_URI = "sqlite:////test.db"
if MODE == 'production':
config = ProductionConfig()
else:
config = DevelopConfig()
# -*- coding: utf-8 -*-
from gevent import monkey
monkey.patch_all()
import logging
from tornado.wsgi import WSGIContainer
from tornado.web import Application, FallbackHandler
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from flask_script import Manager
from flask_migrate import Migrate
from multiprocessing import cpu_count
from application.app import create_app, db
from application.config import config
# 根据配置初始化app
app = create_app(config)
migrate = Migrate(app, db)
manager = Manager(app)
@manager.command
def run():
"""
生产模式启动命令函数
To use: python3 manager.py run
"""
# app.logger.setLevel(app.config.get('LOG_LEVEL', logging.INFO))
# service_config = {
# 'bind': app.config.get('BIND', '0.0.0.0:3000'),
# 'workers': app.config.get('WORKERS', cpu_count() * 2 + 1),
# 'worker_class': 'gevent',
# 'worker_connections': app.config.get('WORKER_CONNECTIONS', 10000),
# 'backlog': app.config.get('BACKLOG', 2048),
# 'timeout': app.config.get('TIMEOUT', 60),
# 'loglevel': app.config.get('LOG_LEVEL', 'info'),
# 'pidfile': app.config.get('PID_FILE', 'run.pid'),
# }
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(3000, address='127.0.0.1')
# wsgi_app = WSGIContainer(app)
# application = Application([
# (r'.*', FallbackHandler, dict(fallback=wsgi_app))
# ], **service_config)
# application.listen(3000)
IOLoop.instance().start()
@manager.command
def debug():
"""
debug模式启动命令函数
To use: python3 manager.py debug
"""
# app.logger.setLevel(logging.DEBUG)
print("start from here......")
app.run(debug=True, port=3000, host='127.0.0.1')
if __name__ == '__main__':
manager.run()
# -*- coding: utf-8 -*-
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.ext.declarative import declarative_base
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.ext.declarative import declared_attr, declarative_base
class Base(object):
class BaseModelMixin(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
def __tablename__(self):
return self.__name__.lower()
__table_args__ = {'mysql_engine': 'InnoDB'}
# __table_args__ = {'mysql_engine': 'InnoDB'}
id = Column(Integer, primary_key=True)
Base = declarative_base(cls=Base)
BaseModel = declarative_base(cls=BaseModelMixin)
class MyMixin(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
def __tablename__(self):
return self.__name__.lower()
__table_args__ = {'mysql_engine': 'InnoDB'}
# __table_args__ = {'mysql_engine': 'InnoDB'}
__mapper_args__= {'always_refresh': True}
id = Column(Integer, primary_key=True)
class MyModel(MyMixin, Base):
# example:
class MyModel(MyMixin, BaseModel):
name = Column(String(1000))
db = SQLAlchemy()
\ No newline at end of file
......@@ -2,27 +2,34 @@
import uuid
from datetime import datetime
from . import db
from application.app import db
class BaseModel(db.Model):
create_date = db.Column(db.DateTime, default=datetime.now)
# Flask-SQLAlchemy创建table时,如何声明基类(这个类不会创建表,可以被继承)
# 方法就是把__abstract__这个属性设置为True,这个类为基类,不会被创建为表!
__abstract__ = True
create_at = db.Column(db.DateTime, default=datetime.now)
create_by = db.Column(db.String(64))
update_date = db.Column(db.DateTime, default=datetime.now)
update_at = db.Column(db.DateTime, default=datetime.now)
update_by = db.Column(db.String(64))
remarks = db.Column(db.String(255), default="")
del_flag = db.Column(db.BOOLEAN, default=0)
is_delete = db.Column(db.BOOLEAN, default=0)
class PrimaryModel(BaseModel):
__abstract__ = True
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
uuid = db.Column(db.String(64), primary_key=True, default=uuid.uuid1)
class AutoBaseModel(BaseModel):
__abstract__ = True
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
sort = db.Column(db.Integer, default=0)
class UuidBaseModel(BaseModel):
__abstract__ = True
id = db.Column(db.String(64), primary_key=True, default=uuid.uuid1)
sort = db.Column(db.Integer, default=0)
class SortBaseModel(BaseModel):
__abstract__ = True
sort = db.Column(db.Integer, default=0)
\ No newline at end of file
alembic==1.6.5
aniso8601==9.0.1
appdirs==1.4.4
asgiref==3.3.4
cffi==1.14.5
click==8.0.1
colorama==0.4.4
Flask==2.0.1
Flask-JWT-Extended==4.2.1
flask-marshmallow==0.14.0
Flask-Migrate==3.0.1
Flask-RESTful==0.3.9
Flask-Script==2.0.6
Flask-SQLAlchemy==2.5.1
fs==2.4.13
gevent==21.1.2
greenlet==1.1.0
gunicorn==20.1.0
h11==0.12.0
hashids==1.3.1
itsdangerous==2.0.1
Jinja2==3.0.1
Mako==1.1.4
MarkupSafe==2.0.1
marshmallow==3.12.1
marshmallow-sqlalchemy==0.26.1
pycparser==2.20
PyJWT==2.1.0
python-dateutil==2.8.1
python-editor==1.0.4
pytz==2021.1
six==1.16.0
SQLAlchemy==1.4.17
tornado==6.1
uvicorn==0.14.0
Werkzeug==2.0.1
zope.event==4.5.0
zope.interface==5.4.0
# -*- coding: utf-8 -*-
from flask import Blueprint
from flask_restful import Api
from . import .
api_v1 = Blueprint('api_v1', __name__)
api = Api(api_v1)
api.add_resource(area.AreaListResource, '/area/', endpoint='area')
api.add_resource(area.AreaResource, '/area/<int:id>')
api.add_resource(cache_data.CacheDataListResource, '/cache', endpoint='cache')
api.add_resource(company_contact.ContactListResource, '/companyPhone/')
api.add_resource(company_contact.ContactResource, '/companyPhone/<int:id>')
api.add_resource(company.CompanyListResource, '/company/')
api.add_resource(company.ExtendCompanyResource, '/company/openApi')
api.add_resource(company.CompanyResource, '/company/<string:id>')
api.add_resource(dictionary.DictListResource, '/dictionary/')
api.add_resource(dictionary.ExtendDictResource, '/dictionary/groupBy')
api.add_resource(dictionary.DictResource, '/dictionary/<int:id>')
api.add_resource(equipment_attrs.AttrsListResource, '/equipmentAttributes/')
api.add_resource(equipment_attrs.AttrsResource, '/equipmentAttributes/<string:id>')
api.add_resource(equipment_attrs.AttrValuesListResource, '/equipmentAttributes/attr/')
api.add_resource(equipment_attrs.AttrValuesResource, '/equipmentAttributes/attr/<string:id>')
api.add_resource(equipment_login.LoginListResource, '/equipmentLoginLog/')
api.add_resource(equipment_msg.MessageListResource, '/equipmentMessage/')
api.add_resource(equipment_type.TypeListResource, '/equipmentTypes/')
api.add_resource(equipment_type.TypeResource, '/equipmentTypes/<string:id>')
api.add_resource(equipment_phone.PhoneListResource, '/equipmentPhone/')
api.add_resource(equipment_phone.PhoneResource, '/equipmentPhone/<int:id>')
api.add_resource(terminal_code.CodeListResource, '/equipmentTerminalCode/')
api.add_resource(equipment_operate.OperateLogListResource, '/terminalLog/')
api.add_resource(equipment_parameters.ParameterListResource, '/equipmentParameter/')
api.add_resource(equipment_parameters.ParameterResource, '/equipmentParameter/<int:id>')
api.add_resource(equipment_parameters.CustomParametersResource, '/parameters/custom/')
api.add_resource(equipment_history_data.HistoryDataResource, '/historyData/<string:id>/')
api.add_resource(equipment_history_data.HistoryChartResource, '/historyData/chart/<string:id>/')
api.add_resource(equipment_now_data.NowDataListResource, '/equipmentNowData/')
api.add_resource(equipment_now_data.NowDataResource, '/equipmentNowData/<string:id>')
api.add_resource(equipment_now_data.ChartDataResource, '/equipmentNowData/chart/<string:id>')
api.add_resource(equipment.EquipmentListResource, '/equipment/')
api.add_resource(equipment.EquipmentResource, '/equipment/<string:id>')
api.add_resource(equipment.ExtendEquipmentResource, '/equipment/exists')
api.add_resource(equipment.EquipmentsConfig, '/equipment/config')
api.add_resource(equipment.LabEquipmentResource, '/equipment/getLabEquipment')
api.add_resource(equipment.TerminalCodeResource, '/equipment/getTerminalCode')
api.add_resource(user.UserListResource, '/user/')
api.add_resource(user.UserResource, '/user/<string:id>')
api.add_resource(user.ExtendUserResource, '/user/updateOperation/<string:id>')
api.add_resource(user_weixin.UserWeiXinListResource, '/userWeixin/')
api.add_resource(user_weixin.UserWeiXinResource, '/userWeixin/<string:id>')
api.add_resource(warning_report.WarningReportListResource, '/warningReport/')
api.add_resource(warning_type.WarningTypeListResource, '/warningTypes/')
api.add_resource(warning_type.WarningTypeResource, '/warningTypes/<string:id>')
api.add_resource(firmware.FirmwareListResource, '/firmware/')
api.add_resource(firmware.FirmwareResource, '/firmware/<int:id>')
api.add_resource(menu.MenuListResource, '/menu/')
api.add_resource(menu.MenuResource, '/menu/<string:id>')
api.add_resource(operation.OperationListResource, '/operation/')
api.add_resource(operation.OperationResource, '/operation/<string:id>')
api.add_resource(operation.UserOperationResource, '/operation/getUserOperation/<string:user>')
api.add_resource(operation.MenuOperationResource, '/operation/getMenuOperation/')
api.add_resource(role.RoleListResource, '/role/')
api.add_resource(role.RoleResource, '/role/<string:id>')
api.add_resource(role_user.RoleUserListResource, '/roleUser/')
api.add_resource(role_permission.RolePermissionListResource, '/rolePermission/')
api.add_resource(role_permission.RolePermissionResource, '/rolePermission/<string:id>')
api.add_resource(role_permission.ExtendRolePermission, '/rolePermission/type/<string:type>')
api.add_resource(permission.PermissionListResource, '/permission/')
api.add_resource(permission.PermissionResource, '/permission/<string:id>')
api.add_resource(permission_related.RelatedListResource, '/permissionRelated/')
api.add_resource(permission_related.ExtendRelatedResource, '/permissionRelated/batch/')
api.add_resource(permission_related.RelatedResource, '/permissionRelated/<string:id>')
api.add_resource(public.UserInfoResource, '/public/login')
api.add_resource(public.FileResource, '/public/fileRequest/')
api.add_resource(public.WeixinLogin, '/public/weixin/login/')
api.add_resource(public.BackstageResource, '/public/equipmentMap')
api.add_resource(public.SystemResource, '/public/dashboard')
api.add_resource(public.LogoutResource, '/public/logout')
api.add_resource(containers.ContainerListResource, '/containers/')
api.add_resource(synchronous.CompanySyncResource, '/synchronous/company/')
api.add_resource(synchronous.EquipmentSyncResource, '/synchronous/equipment/')
api.add_resource(synchronous.CompanyThirdPartySyncResource, '/synchronous/thirdparty/company/')
api.add_resource(synchronous.EquipmentThirdPartySyncResource, '/synchronous/thirdparty/equipment/')
api.add_resource(synchronous.UserSyncResource, '/synchronous/user/')
api.add_resource(report.ReportResource, '/report/')
api.add_resource(openapi.APIEquipmentResource, '/openapi/equipment/')
\ No newline at end of file
# -*- coding: utf_8 -*-
############################
# Signals-Slots
# 信号槽
############################
class PySignal(object):
"""
Simple event class used to provide hooks for different types of events in Locust.
Here's how to use the EventHook class::
my_event = PySignal()
def on_my_event(a, b, **kw):
print "Event was fired with arguments: %s, %s" % (a, b)
my_event += on_my_event
my_event.fire(a="foo", b="bar")
my_event.emit(a="foo", b="bar")
"""
def __init__(self):
self._handlers = []
def __iadd__(self, handler):
return self.connect(handler)
def __isub__(self, handler):
return self.disconnect(handler)
def connect(self, handler):
self._handlers.append(handler)
return self
def disconnect(self, handler):
self._handlers.remove(handler)
return self
def fire(self, *args, **kwargs):
return self.emit(*args, **kwargs)
def emit(self, *args, **kwargs):
rets = {}
for handler in self._handlers:
ret = handler(*args, **kwargs)
rets[handler.__name__] = ret
if len(rets) == 1:
return list(rets.values())[0] # list()用来兼容python3
return rets
if __name__ == '__main__':
my_event = PySignal()
def on_my_event(a, b, **kw):
print(a, b)
print(kw)
my_event.connect(on_my_event)
my_event.fire(1, 2, c="foo", d="bar")
my_event.emit(3, 4, e="foo", f="bar")
......@@ -5,9 +5,9 @@
# 日志
############################
import os
import logging
from logging.handlers import RotatingFileHandler
import os
logPath = os.getcwd() + os.path.sep + "logs"
if not os.path.exists(logPath):
......
......@@ -26,6 +26,6 @@ class ResponseCode(object):
def response_result(code, msg=None, data=None, **kwargs):
if msg is None:
msg = code[1]
result = { 'code': code[0], 'message': msg, 'data': data }
result = { 'code': code[0], 'msg': msg, 'data': data }
result.update(kwargs)
return result
\ No newline at end of file
# -*- coding: utf-8 -*-
from typing import (
Any,
Optional,
Dict,
Mapping,
List,
Tuple,
Match,
Callable,
Type,
Sequence,
)
class Klass:
def __init__(self):
pass
klass = Klass()
def dict2obj(dictionary):
klass.__dict__.update(dictionary)
return klass
class ObjectDict(Dict[str, Any]):
"""Makes a dictionary behave like an object, with attribute-style access."""
def __getattr__(self, name: str) -> Any:
try:
return self[name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name: str, value: Any) -> None:
self[name] = value
if __name__ == "__main__":
d = { 'a': 1, 'b': 2 }
print(dict2obj(d))
\ No newline at end of file
This diff is collapsed.
# 模板文件定义标准
## model
### 字段类型
字段类型只能定义如下类型:
- Integer
- String
- Boolean
## view
## controller
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -2,13 +2,15 @@
from flask import Blueprint
from flask_restful import Api
from . import {% for i, router in enumerate(routers) in %}{% if i != 0 %},{% endif %}{{ router }}{% endfor %}
{%- for item in config %}
from . import {{item["name"]}}
{%- endfor %}
api_v1 = Blueprint('api_v1', __name__)
api = Api(api_v1)
{% for v in views %}
api.add_resource({{ name }}.{{ clasName }}, '{{ path }}'{% if endpoint %}, endpoint={{ endpoint }}{% endif %})
{% for item in config %}
api.add_resource({{ item['name'] }}.{{ item['name'] | letterUpper }}Resource, '/{{ item['name'] }}{{ item['view']['get']['path'] }}'{% if item['view']['get']['endpoint'] %}, endpoint={{ item['view']['get']['endpoint'] }}{% endif %})
api.add_resource({{ item['name'] }}.{{ item['name'] | letterUpper }}ResourceList, '/{{ item['name'] }}{{ item['view']['getList']['path'] }}'{% if item['view']['getList']['endpoint'] %}, endpoint='{{ item['view']['getList']['endpoint'] }}'{% endif %})
{% endfor %}
#!/usr/bin/env python
# -*- coding: utf_8 -*-
from webcreator.event import PySignal
class SignalManager(object):
{%- for item in config %}
{%- for key, value in item['view'].items() %}
action{{ key | letterUpper }}{{ item.get("name") | letterUpper }} = PySignal()
{%- endfor %}
{%- endfor %}
def __init__(self):
super().__init__()
signalManager = SignalManager()
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment