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))
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 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():
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)
def hanleRender():
pass
target_file = os.sep.join(["models", "{}.py".format(config.get("name"))])
handleRender(config, 'model.tpl', target_file, fields=fields, extend=extend, application=application)
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.
This diff is collapsed.
This diff is collapsed.
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