Commit 878a236a authored by wanli's avatar wanli

后端自动代码生成框架初步搭建完成

parent a6bdce65
......@@ -24,4 +24,4 @@ pip3 install -r requirements.txt
如果有新安装的包,需要更新requirements.txt文件
```
pip freeze > requirements.txt
```
\ No newline at end of file
```
......@@ -16,7 +16,7 @@ class BuildLogs(db.Entity):
app = Required("Apps", reverse="app_build_log")
app_path = Optional(str, default="")
app_info = Optional(Json, default={})
source = Optional(int, default="") # 打包来源 1管理中心 2后端接口
source = Optional(int, default=0) # 打包来源 1管理中心 2后端接口
create_at = Required(datetime, default=datetime.now)
create_by = Required("User", reverse='build_logs_creator') # BuildLogs与User一对一关系
update_at = Required(datetime, default=datetime.now)
......
......@@ -2,38 +2,6 @@ from datetime import datetime
from . import BaseSchema
from marshmallow import fields, validate, RAISE, INCLUDE, EXCLUDE
class AddProjectSchema(BaseSchema):
type = fields.String(required=False, allow_none=True)
title = fields.String(required=True, validate=validate.Length(min=2, max=50))
code = fields.String(required=False, allow_none=True)
amount = fields.Decimal(required=False, default=0, allow_none=True) # 总金额
consult_type = fields.String(required=False, allow_none=True) # 咨询项目类型
contract_sign_at = fields.String(required=False, allow_none=True) # 项目签订日期
party_a = fields.String(required=False, allow_none=True) # 项目甲方
party_b = fields.String(required=False, allow_none=True) # 项目乙方
leader = fields.String(required=False, allow_none=True) # 项目开发人
level = fields.String(required=False, allow_none=True) # 项目开发级别
source = fields.String(required=False, allow_none=True) # 项目来源
introducer = fields.String(required=False, allow_none=True) # 同业引进人
standard_type = fields.String(required=False, allow_none=True) # 体系类型
review_type = fields.String(required=False, allow_none=True) # 审核类型
customer_addr = fields.String(required=False, allow_none=True) # 客户地址
customer_contact = fields.String(required=False, allow_none=True) # 客户联系人
customer_phone = fields.String(required=False, allow_none=True) # 客户联系电话
ascription = fields.String(required=False, allow_none=True) # 项目归属
risk = fields.String(required=False, allow_none=True) # 风险级别
people_nums = fields.Int(required=False, allow_none=True) # 人数
start_time = fields.DateTime(required=True, default=datetime.now) # 项目开始时间
end_time = fields.DateTime(required=True, default=datetime.now) # 项目结束时间
users = fields.List(fields.String(), required=True) # 项目参与者
flow = fields.List(fields.Dict(), required=False, allow_none=True) # 流程节点列表
payback = fields.List(fields.Dict(), required=False, allow_none=True) # 回款计划列表
production = fields.Dict(required=False, allow_none=True) # 项目费用相关
remarks = fields.String(required=False, allow_none=True) # 备注
class Meta:
unknown = EXCLUDE
class QuerySchema(BaseSchema):
project = fields.UUID(required=True)
......
......@@ -131,6 +131,7 @@ def filter_dict(source: dict, rules_list: list):
return result
def sql_filter(sql):
return re.sub(r"[\"\\/*\'=\-#;<>+%$()!@]", "", sql)
......
......@@ -18,9 +18,7 @@ from .app_logs import appLogs_api
from .ws import NotifyHandler, ThreadNotifyHandler
from model import fullStackDB
from fullstack.response import ResponseCode, response_result
from app import config, signalManager
from flask_login import LoginManager
from app import config
logger = logging.getLogger(__name__)
......
......@@ -7,4 +7,63 @@
- https://flask.palletsprojects.com/en/1.1.x/api/
- 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/
\ No newline at end of file
- 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_ERRORRROR, data=data)))
else:
return abort(jsonify(response_result(ResponseCode.PARAMETER_ERRORRROR, 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()
actionGetArea = PySignal()
actionPutArea = 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
def initConnect():
signalManager.actionPostArea.connect(areaManager.post)
signalManager.actionDeleteArea.connect(areaManager.delete)
signalManager.actionGetArea.connect(areaManager.get)
signalManager.actionPutArea.connect(areaManager.put)
initConnect()
\ 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
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)
# wsgi_app = WSGIContainer(app)
# application = Application([
# (r'.*', FallbackHandler, dict(fallback=wsgi_app))
# ], **service_config)
# application.listen(3000, address='127.0.0.1')
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 datetime import datetime
from .base import PrimaryModel
class AreaModel(PrimaryModel):
__tablename__ = '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)
class AreaSchema(ma.SQLAlchemySchema):
class Meta:
model = AreaModel
areaCode = ma.auto_field()
areaName = ma.auto_field()
level = ma.auto_field()
cityCode = ma.auto_field()
center = ma.auto_field()
parentId = ma.auto_field()
hasChildren = ma.auto_field()
area_schema = AreaSchema()
areas_schema = AreaSchema(many=True)
\ No newline at end of file
# -*- 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
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
api_v1 = Blueprint('api_v1', __name__)
api = Api(api_v1)
api.add_resource(area.AreaResource, '/area/<string:uuid>')
api.add_resource(area.AreaResourceList, '/area', endpoint='/')
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 area_schema
from webcreator.response import ResponseCode, response_result
class AreaResource(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 = area_schema.load(json_payload)
result = signalManager.actionGetArea.emit(**data)
json_dumps = area_schema.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 = area_schema.load(json_payload)
result = signalManager.actionPostArea.emit(**data)
json_dumps = area_schema.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 = area_schema.load(json_payload)
result = signalManager.actionGetArea.emit(**data)
json_dumps = area_schema.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 = area_schema.load(json_payload)
result = signalManager.actionPutArea.emit(**data)
json_dumps = area_schema.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 = area_schema.load(json_payload)
result = signalManager.actionDeleteArea.emit(**data)
json_dumps = area_schema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
\ No newline at end of file
# -*- 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, unicode):
self.write_message(msg, binary)
else:
self.write_message(repr(msg), binary)
except WebSocketClosedError as 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):
# 将所有有默认值的字段分为一组,没有默认值的字段分为另一组
# 生成模板代码时,无默认值的字段在前,有默认值的字段字在后
pass
target_file = os.sep.join(["models", "{}.py".format(config.get("name"))])
handleRender(config, 'model.tpl', target_file)
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):
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 })
# 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)
handleView(cfg)
handleController(cfg)
handleResources(config.get("apis"))
handleSignal(config.get("apis"))
def readConfig():
result = {}
......@@ -21,6 +84,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_ERRORRROR, data=data)))
else:
return abort(jsonify(response_result(ResponseCode.PARAMETER_ERRORRROR, 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)
# wsgi_app = WSGIContainer(app)
# application = Application([
# (r'.*', FallbackHandler, dict(fallback=wsgi_app))
# ], **service_config)
# application.listen(3000, address='127.0.0.1')
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
#!/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, unicode):
self.write_message(msg, binary)
else:
self.write_message(repr(msg), binary)
except WebSocketClosedError as 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)
from models import db
from models.{{ model['tableName'] }} import {{ model['className'] }}
from datetime import datetime
from application.app import db
from models.{{ config['model']['tableName'] }} import {{ config['model']['className'] }}
from webcreator.utils import ResponseCode, response_result
class {{ contronller['className'] }}(object):
class {{ config['controller']['className'] }}(object):
def __init__(self):
super({{ contronller['className'] }}, self).__init__()
super().__init__()
def get(self, params):
# handle business
result = {{ model['className'] }}.query.filter(*filters).order_by({{ model['className'] }}.areaId).paginate(params['pageNum'], params['pageSize'], error_out=False)
filters = []
result = {{ config['model']['className'] }}.query.filter(*filters).order_by({{ config['model']['className'] }}.areaId).paginate(params.get('page', 1), params.get('pageSize', 10), error_out=False)
return result
def post(self, params):
def post(self, params, jwt=None):
# handle business
result = {{ model['className'] }}.query.filter({{ model['className'] }}.areaName == params['areaName']).first()
if result and result.del_flag:
result.del_flag = False
result = {{ config['model']['className'] }}.query.filter({{ config['model']['className'] }}.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 pretty_result(code.OK)
elif result and result.del_flag == False:
return pretty_result(code.EXISTS_ERROR)
return response_result(ResponseCode.OK)
elif result and result.is_delete == False:
return response_result(ResponseCode.EXISTS_ERROR)
result = {{ model['className'] }}(**params)
result = {{ config['model']['className'] }}(**params)
db.session.add(result)
db.session.commit()
return pretty_result(code.OK)
return response_result(ResponseCode.OK)
def put(self, id, params):
def put(self, id, params, jwt=None):
# handle business
result = {{ model['className'] }}.query.get(id)
if not result: return pretty_result(code.NO_DATA)
result = {{ config['model']['className'] }}.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)
......@@ -39,15 +42,17 @@ class {{ contronller['className'] }}(object):
result.update_date = datetime.now()
db.session.commit()
else:
return pretty_result(code.PARAM_NULL)
return response_result(ResponseCode.PARAM_NULL)
def delete(self, id):
def delete(self, id, jwt=None):
# handle business
result = {{ model['className'] }}.query.get(id)
if not result: return pretty_result(code.NO_DATA_FOUND)
result = {{ config['model']['className'] }}.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.del_flag = True
result.is_delete = True
db.session.delete(result)
db.session.commit()
\ No newline at end of file
db.session.commit()
{{ config["name"] }}Manager = {{ config['controller']['className'] }}()
\ No newline at end of file
# -*- coding: utf-8 -*-
from . import db
from application.app import db, ma
from datetime import datetime
from .base import BaseModel, PrimaryModel
class {{ className }}(db.Model):
__tablename__ = '{{ tableName }}'
{% for key, value in fields.items() %}
{% if value.get('primaryKey', None) %}
value.get('name') = db.Column(db.{{ value.get('dataType') }}, primary_key = True, {% if value.get('autoIncrement') %}autoincrement = True{% endif %})
{% else %}
value.get('name') = db.Column(db.{{ value.get('dataType') }}{% if value.get("length", None) %}(value.get("length")){% endif %}{% if value.get("index", False) %}, index = True{% endif %}{% if value.get("default", None) %}, default = value.get("default"){% endif %})
{% endif %}
{% endfor %}
from .base import PrimaryModel
class {{ config['model']['className'] }}(PrimaryModel):
__tablename__ = '{{ config['model']['tableName'] }}'
{% for value in config['model']['fields'] %}
{%- if value.get('primaryKey', None) %}
{{ value.get('name') }} = db.Column(db.{{ value.get('dataType') }}, primary_key = True, {% if value.get('autoIncrement') %}autoincrement = True{% endif %})
{%- elif value.get('dataType') == "Int" or value.get('dataType') == "Integer" %}
{{ value.get('name') }} = db.Column(db.{{ value.get('dataType') }}{% if value.get("length", None) %}{% endif %}{% if value.get("index", False) %}, index = True{% endif %}{% if value.get("default", None) %}, default = {{value.get("default")}}{% endif %})
{%- else %}
{{ value.get('name') }} = db.Column(db.{{ value.get('dataType') }}{% if value.get("length", None) %}({{value.get("length")}}){% endif %}{% if value.get("index", False) %}, index = True{% endif %}{% if value.get("default", None) %}, default = {{value.get("default")}}{% endif %})
{%- endif %}
{%- endfor %}
# __table_args__ = (
# db.Index('idx_areaCode', 'areaCode', mysql_using='btree'),
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self{% for for key, value in fields.items() %}, {{ value.get("name") }}{% endfor %}):
{% for key, value in fields.items() %}
def __init__(self{% for value in config['model']['fields'] %}, {{ value.get("name") }}{% endfor %}):
{%- for value in config['model']['fields'] %}
self.{{ value.get("name") }} = {{ value.get("name") }}
{% endfor %}
{%- endfor %}
def __repr__(self):
return '<{{ className }} %r>' % (self.{{ fields[0]["name"] }})
return '<{{ config['model']['className'] }} %r>' % (self.{{ config['model']['fields'][0]["name"] }})
class {{ config['name'] | letterUpper }}Schema(ma.SQLAlchemySchema):
class Meta:
model = {{ config['model']['className'] }}
{%- if config['model']['foreignKey'] %}
include_fk = {{ config['model']['foreignKey'] }}
{% endif %}
{%- for value in config['model']['fields'] %}
{{ value.get("name") }} = ma.auto_field()
{%- endfor %}
{{ config['name'] }}_schema = {{ config['name'] | letterUpper }}Schema()
{{ config['name'] }}s_schema = {{ config['name'] | letterUpper }}Schema(many=True)
\ No newline at end of file
......@@ -3,12 +3,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['controller']['className'] }}, '{{ item['view']['put']['path'] }}'{% if item['view']['put']['endpoint'] %}, endpoint={{ item['view']['put']['endpoint'] }}{% endif %})
api.add_resource({{ item['name'] }}.{{ item['controller']['className'] }}List, '{{ item['view']['post']['path'] }}'{% if item['view']['post']['endpoint'] %}, endpoint='{{ item['view']['post']['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()
#!/usr/bin/env python
# -*- coding: utf_8 -*-
from application.app import signalManager
{%- for api in config %}
from .{{ api['name'] }} import {{ api["name"] }}Manager
{%- endfor %}
def initConnect():
{%- for api in config %}
{%- for key, value in api.get("view").items() %}
signalManager.action{{ key | letterUpper }}{{ api.get("name") | letterUpper }}.connect({{ api.get("name") }}Manager.{{ key }})
{%- endfor %}
{%- endfor %}
initConnect()
from flask import current_app
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 common import code, pretty_result
from application.signal_manager import signalManager
from models.{{ config['name'] }} import {{ config['name'] }}_schema
from webcreator.response import ResponseCode, response_result
class {{ className }}(Resource):
class {{ config['controller']['className'] | letterUpper }}(Resource):
def __init__(self):
self.parser = RequestParser()
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
{% if config["view"]["post"] %}
@jwt_required
{%- endif %}
def get(self):
self.parser.add_argument("currentPage", type=int, location="args", default=1)
self.parser.add_argument("pageSize", type=int, location="args", default=15)
self.parser.add_argument("equipment", type=int, location="args", required=False)
args = self.parser.parse_args()
# 特殊参数,即不是从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 = {{ config['name'] }}_schema.load(json_payload)
result = signalManager.actionGet{{ config["name"] | letterUpper }}.emit(**data)
json_dumps = {{ config['name'] }}_schema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return pretty_result(code.DB_ERROR)
\ No newline at end of file
return response_result(ResponseCode.DB_ERROR)
{% if config["view"]["post"] %}
@jwt_required
{%- endif %}
def post(self):
try:
json_payload = request.json
data = {{ config['name'] }}_schema.load(json_payload)
result = signalManager.actionPost{{ config["name"] | letterUpper }}.emit(**data)
json_dumps = {{ config['name'] }}_schema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
class {{ config['controller']['className'] | letterUpper }}List(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
{% if config["view"]["post"] %}
@jwt_required
{%- endif %}
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 = {{ config['name'] }}_schema.load(json_payload)
result = signalManager.actionGet{{ config["name"] | letterUpper }}.emit(**data)
json_dumps = {{ config['name'] }}_schema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
{% if config["view"]["post"] %}
@jwt_required
{%- endif %}
def put(self):
try:
json_payload = request.json
data = {{ config['name'] }}_schema.load(json_payload)
result = signalManager.actionPut{{ config["name"] | letterUpper }}.emit(**data)
json_dumps = {{ config['name'] }}_schema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
{% if config["view"]["post"] %}
@jwt_required
{%- endif %}
def delete(self):
try:
json_payload = request.json
data = {{ config['name'] }}_schema.load(json_payload)
result = signalManager.actionDelete{{ config["name"] | letterUpper }}.emit(**data)
json_dumps = {{ config['name'] }}_schema.dump(result)
return jsonify(json_dumps), 200
except Exception as e:
current_app.logger.error(e)
return response_result(ResponseCode.DB_ERROR)
\ No newline at end of file
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