调整目录结构
@@ -1,5 +0,0 @@
|
|||||||
FLASK_APP=main.py
|
|
||||||
FLASK_ENV=development
|
|
||||||
FLASK_DEBUG=1
|
|
||||||
FLASK_RUN_HOST = 127.0.0.1
|
|
||||||
FLASK_RUN_PORT = 5000
|
|
||||||
@@ -57,90 +57,23 @@ Pear Admin Flask 分为 Common / Simple 两个版本:
|
|||||||
|
|
||||||
```
|
```
|
||||||
Pear Admin Flask
|
Pear Admin Flask
|
||||||
│
|
├─applications # 应用
|
||||||
├─applications
|
│ ├─configs # 配置文件
|
||||||
│ │
|
│ │ ├─ common.py # 普通配置
|
||||||
│ ├─config
|
│ │ └─ config.py # 配置文件对象
|
||||||
│ │ │
|
│ ├─extensions # 注册插件
|
||||||
│ │ ├─ common.py #普通配置
|
│ ├─models # 数据模型
|
||||||
│ │ │
|
│ ├─static # 静态资源文件
|
||||||
│ │ └─ database.py #数据库配置
|
│ ├─templates # 静态模板文件
|
||||||
│ │
|
│ └─views # 视图部分
|
||||||
│ ├─models
|
│ ├─admin # 后台管理视图模块
|
||||||
│ │ │
|
│ └─index # 前台视图模块
|
||||||
│ │ └─admin.py #基本模型
|
├─docs # 文档说明(占坑)
|
||||||
│ │
|
├─migrations # 迁移文件记录
|
||||||
│ ├─service
|
├─requirement # 依赖文件
|
||||||
│ │ │
|
├─test # 测试文件夹(占坑)
|
||||||
│ │ ├─admin
|
└─.env # 项目的配置文件
|
||||||
│ │ │ │
|
|
||||||
│ │ │ ├─ file.py #file视图的数据操作
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ ├─ index.py #index视图的数据操作
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ ├─ power.py #power视图的数据操作
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ ├─ role.py #role视图的数据操作
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ └─ user.py #user视图的数据操作
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─ admin_log.py #存储日志
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─ deBug.py #deBug工具栏初始化
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─ login.py #flask_login初始化
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─ CaptchaTool.py #验证码
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─ OriginalDb.py #原生sql查询封装
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─ route_auth.py #权限
|
|
||||||
│ │ │
|
|
||||||
│ │ └─ upload.py #上传
|
|
||||||
│ │
|
|
||||||
│ └─views
|
|
||||||
│ │
|
|
||||||
│ ├─admin #前台视图
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─index.py #主视图
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─user.py #用户视图
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─role.py #角色视图
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─power.py #权限视图
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─monitor.py #系统监控
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─file.py #文件上传
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─admin_log.py #系统日志
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─context_processor.py #全局模板函数注册
|
|
||||||
│ │ │
|
|
||||||
│ │ ├─error.py #错误处理
|
|
||||||
│ │ │
|
|
||||||
│ │ └─init.py #蓝图注册
|
|
||||||
│ │
|
|
||||||
│ └─index #前台视图
|
|
||||||
│
|
|
||||||
├─dev #数据库初始化
|
|
||||||
│
|
|
||||||
├─migrations
|
|
||||||
│
|
|
||||||
├─readmes
|
|
||||||
│
|
|
||||||
├─static #静态资源
|
|
||||||
│ │
|
|
||||||
│ └─upload #文件上传地址
|
|
||||||
│
|
|
||||||
└─templates
|
|
||||||
│
|
|
||||||
├─admin #前台模板
|
|
||||||
│
|
|
||||||
├─errors #错误模板
|
|
||||||
│
|
|
||||||
└─index #前台模板
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -152,10 +85,10 @@ Pear Admin Flask
|
|||||||
git clone https://gitee.com/pear-admin/pear-admin-flask
|
git clone https://gitee.com/pear-admin/pear-admin-flask
|
||||||
|
|
||||||
# 安 装
|
# 安 装
|
||||||
pip install -r requirement.txt
|
pip install -r requirement\requirement-dev.txt
|
||||||
|
|
||||||
# 配 置
|
# 配 置
|
||||||
applications\config\database.py
|
.env
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -189,14 +122,8 @@ python -m venv venv
|
|||||||
#### 运行项目
|
#### 运行项目
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 进 入 目 录
|
|
||||||
cd dev
|
|
||||||
|
|
||||||
# 初 始 化 数 据 库
|
# 初 始 化 数 据 库
|
||||||
python initDb.py
|
python test\init_databases.py
|
||||||
|
|
||||||
# 如 果 报 模 块 路 径 错 误
|
|
||||||
python dev/initDb.py
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -207,6 +134,6 @@ python dev/initDb.py
|
|||||||
|
|
||||||
| | |
|
| | |
|
||||||
|---------------------|---------------------|
|
|---------------------|---------------------|
|
||||||
|  |  |
|
|  |  |
|
||||||
| |  |
|
| |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from applications import create_app
|
||||||
|
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
from flask_uploads import configure_uploads
|
||||||
|
|
||||||
|
from applications.common.utils.upload import photos
|
||||||
|
from applications.configs import common
|
||||||
|
from applications.extensions import init_plugs
|
||||||
|
from applications.view import init_view
|
||||||
|
from applications.configs import config
|
||||||
|
|
||||||
|
|
||||||
|
def create_app(config_name=None):
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
if not config_name:
|
||||||
|
# 尝试从本地环境中读取
|
||||||
|
config_name = os.getenv('FLASK_CONFIG', 'development')
|
||||||
|
|
||||||
|
# 引入数据库配置
|
||||||
|
app.config.from_object(common)
|
||||||
|
app.config.from_object(config[config_name])
|
||||||
|
# 注册各种插件
|
||||||
|
init_plugs(app)
|
||||||
|
|
||||||
|
# 注册路由
|
||||||
|
init_view(app)
|
||||||
|
|
||||||
|
# 文件上传
|
||||||
|
configure_uploads(app, photos)
|
||||||
|
|
||||||
|
logo()
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
def logo():
|
||||||
|
print('''
|
||||||
|
_____ _ _ ______ _ _
|
||||||
|
| __ \ /\ | | (_) | ____| | | |
|
||||||
|
| |__) |__ __ _ _ __ / \ __| |_ __ ___ _ _ __ | |__ | | __ _ ___| | __
|
||||||
|
| ___/ _ \/ _` | '__| / /\ \ / _` | '_ ` _ \| | '_ \ | __| | |/ _` / __| |/ /
|
||||||
|
| | | __/ (_| | | / ____ \ (_| | | | | | | | | | | | | | | (_| \__ \ <
|
||||||
|
|_| \___|\__,_|_| /_/ \_\__,_|_| |_| |_|_|_| |_| |_| |_|\__,_|___/_|\_\\
|
||||||
|
|
||||||
|
''')
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from applications.models import db
|
from applications.common.utils.validate import xss_escape
|
||||||
from applications.models.admin_dept import Dept, DeptSchema
|
from applications.extensions import db
|
||||||
from applications.models.admin_user import User
|
from applications.models import Dept, DeptSchema
|
||||||
from applications.service.common.curd import model_to_dicts
|
from applications.models import User
|
||||||
from applications.service.common.validate import xss_escape
|
from applications.common.curd import model_to_dicts
|
||||||
|
|
||||||
|
|
||||||
def get_dept_dict():
|
def get_dept_dict():
|
||||||
@@ -12,8 +12,6 @@ def get_dept_dict():
|
|||||||
|
|
||||||
|
|
||||||
def save_dept(req):
|
def save_dept(req):
|
||||||
|
|
||||||
|
|
||||||
address = xss_escape(req.get("address"))
|
address = xss_escape(req.get("address"))
|
||||||
deptName = xss_escape(req.get("deptName"))
|
deptName = xss_escape(req.get("deptName"))
|
||||||
email = xss_escape(req.get("email"))
|
email = xss_escape(req.get("email"))
|
||||||
@@ -1,27 +1,19 @@
|
|||||||
# 字典管理
|
from applications.common.utils.validate import xss_escape
|
||||||
# 查询字典类型
|
from applications.extensions import db
|
||||||
|
from applications.models import DictType, DictData, DictTypeSchema, DictDataSchema
|
||||||
|
from applications.common.curd import model_to_dicts
|
||||||
from applications.models import db
|
|
||||||
from applications.models.admin_dict import DictType, DictData, DictTypeSchema, DictDataSchema
|
|
||||||
from applications.service.common.curd import model_to_dicts
|
|
||||||
from applications.service.common.validate import xss_escape
|
|
||||||
|
|
||||||
# 通过type_code获取字典dict
|
|
||||||
# 例:get_dict('user_sex')
|
|
||||||
# [{'key': '男', 'value': 'boy'}, {'key': '女', 'value': 'girl'}]
|
|
||||||
|
|
||||||
|
|
||||||
def get_dict(typecode: str):
|
def get_dict(typecode: str):
|
||||||
Dict_list = []
|
dict_list = []
|
||||||
if DictType.query.filter_by(type_code=typecode, enable=1).first():
|
if DictType.query.filter_by(type_code=typecode, enable=1).first():
|
||||||
Dicts = DictData.query.filter_by(type_code=typecode, enable=1).all()
|
dicts = DictData.query.filter_by(type_code=typecode, enable=1).all()
|
||||||
for d in Dicts:
|
for d in dicts:
|
||||||
Dict_Dict = {"key": d.data_label, "value": d.data_value}
|
dict_dict = {"key": d.data_label, "value": d.data_value}
|
||||||
Dict_list.append(Dict_Dict)
|
dict_list.append(dict_dict)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
return Dict_list
|
return dict_list
|
||||||
|
|
||||||
|
|
||||||
def get_dict_type(page, limit, type_name):
|
def get_dict_type(page, limit, type_name):
|
||||||
@@ -45,7 +37,7 @@ def get_dict_data(page, limit, type_code):
|
|||||||
return dict_dict, count
|
return dict_dict, count
|
||||||
|
|
||||||
|
|
||||||
# 增加dicttype
|
# 增加 dict type
|
||||||
def save_dict_type(req_json):
|
def save_dict_type(req_json):
|
||||||
description = xss_escape(req_json.get("description"))
|
description = xss_escape(req_json.get("description"))
|
||||||
enable = xss_escape(req_json.get("enable"))
|
enable = xss_escape(req_json.get("enable"))
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
import os
|
import os
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
from applications.models import db
|
|
||||||
from applications.models.admin_photo import Photo, PhotoSchema
|
from applications.common.utils.upload import photos
|
||||||
from applications.service.common.curd import model_to_dicts
|
from applications.extensions import db
|
||||||
from applications.service.upload import photos
|
from applications.models import Photo, PhotoSchema
|
||||||
|
from applications.common.curd import model_to_dicts
|
||||||
|
|
||||||
|
|
||||||
def get_photo(page, limit):
|
def get_photo(page, limit):
|
||||||
photo = Photo.query.order_by(desc(Photo.create_time)).paginate(page=page, per_page=limit, error_out=False)
|
photo = Photo.query.order_by(desc(Photo.create_time)).paginate(page=page, per_page=limit, error_out=False)
|
||||||
count = Photo.query.count()
|
count = Photo.query.count()
|
||||||
data = model_to_dicts(Schema=PhotoSchema,model=photo.items)
|
data = model_to_dicts(Schema=PhotoSchema, model=photo.items)
|
||||||
return data, count
|
return data, count
|
||||||
|
|
||||||
|
|
||||||
@@ -26,9 +27,9 @@ def upload_one(photo, mime):
|
|||||||
return file_url
|
return file_url
|
||||||
|
|
||||||
|
|
||||||
def delete_photo_by_id(id):
|
def delete_photo_by_id(_id):
|
||||||
photo_name = Photo.query.filter_by(id=id).first().name
|
photo_name = Photo.query.filter_by(id=_id).first().name
|
||||||
photo = Photo.query.filter_by(id=id).delete()
|
photo = Photo.query.filter_by(id=_id).delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
upload_url = current_app.config.get("UPLOADED_PHOTOS_DEST")
|
upload_url = current_app.config.get("UPLOADED_PHOTOS_DEST")
|
||||||
os.remove(upload_url + '/' + photo_name)
|
os.remove(upload_url + '/' + photo_name)
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from flask import session, make_response, current_app
|
from flask import session, make_response, current_app
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from applications.common.utils.gen_captcha import gen_captcha
|
||||||
from applications.models.admin_power import PowerSchema
|
from applications.models.admin_power import PowerSchema
|
||||||
from applications.service.captcha import gen_captcha
|
|
||||||
|
|
||||||
|
|
||||||
# 授权路由存入session
|
# 授权路由存入session
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
from applications.models import db
|
from applications.common.utils.validate import xss_escape
|
||||||
|
from applications.extensions import db
|
||||||
from applications.models.admin_power import Power, PowerSchema2
|
from applications.models.admin_power import Power, PowerSchema2
|
||||||
from applications.models.admin_role import Role
|
from applications.models import Role
|
||||||
from applications.service.common.curd import model_to_dicts
|
from applications.common.curd import model_to_dicts
|
||||||
from applications.service.common.validate import xss_escape
|
|
||||||
|
|
||||||
|
|
||||||
def get_power_dict():
|
def get_power_dict():
|
||||||
@@ -10,6 +10,7 @@ def get_power_dict():
|
|||||||
res = model_to_dicts(Schema=PowerSchema2, model=power)
|
res = model_to_dicts(Schema=PowerSchema2, model=power)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
# 选择父节点
|
# 选择父节点
|
||||||
def select_parent():
|
def select_parent():
|
||||||
power = Power.query.all()
|
power = Power.query.all()
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
from sqlalchemy import and_
|
from sqlalchemy import and_
|
||||||
from applications.models import db
|
|
||||||
from applications.models.admin_role import Role, RoleSchema
|
from applications.common.utils.validate import xss_escape
|
||||||
|
from applications.extensions import db
|
||||||
|
from applications.models import Role, RoleSchema
|
||||||
from applications.models.admin_power import Power, PowerSchema2
|
from applications.models.admin_power import Power, PowerSchema2
|
||||||
from applications.models.admin_user import User
|
from applications.models import User
|
||||||
|
|
||||||
# 获取角色对象
|
# 获取角色对象
|
||||||
from applications.service.common.curd import model_to_dicts
|
from applications.common.curd import model_to_dicts
|
||||||
from applications.service.common.validate import xss_escape
|
|
||||||
|
|
||||||
|
|
||||||
def get_role_data(page, limit, filters):
|
def get_role_data(page, limit, filters):
|
||||||
@@ -1,33 +1,33 @@
|
|||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from sqlalchemy import and_, desc
|
from sqlalchemy import and_, desc
|
||||||
from applications.models import db
|
from applications.extensions import db
|
||||||
from applications.models.admin_user import User, UserSchema
|
from applications.models import User, UserSchema
|
||||||
from applications.models.admin_role import Role
|
from applications.models import Role
|
||||||
from applications.models.admin_log import AdminLog
|
from applications.models import AdminLog
|
||||||
|
|
||||||
|
# 获取用户的 sqlalchemy 对象分页器
|
||||||
|
from applications.common.curd import model_to_dicts
|
||||||
|
|
||||||
|
|
||||||
# 获取用户的sqlalchemy对象分页器
|
def get_user_data(page, limit, filters, deptId):
|
||||||
from applications.service.common.curd import model_to_dicts
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_data(page, limit, filters,deptId):
|
|
||||||
if deptId:
|
if deptId:
|
||||||
user = User.query.filter_by(dept_id=deptId).filter(and_(*[getattr(User, k).like(v) for k, v in filters.items()])).paginate(page=page,
|
user = User.query.filter_by(dept_id=deptId).filter(
|
||||||
per_page=limit,
|
and_(*[getattr(User, k).like(v) for k, v in filters.items()])).paginate(page=page,
|
||||||
error_out=False)
|
per_page=limit,
|
||||||
|
error_out=False)
|
||||||
else:
|
else:
|
||||||
user = User.query.filter(and_(*[getattr(User, k).like(v) for k, v in filters.items()])).paginate(page=page,
|
user = User.query.filter(and_(*[getattr(User, k).like(v) for k, v in filters.items()])).paginate(page=page,
|
||||||
per_page=limit,
|
per_page=limit,
|
||||||
error_out=False)
|
error_out=False)
|
||||||
count = User.query.count()
|
count = User.query.count()
|
||||||
return user, count
|
return user, count
|
||||||
|
|
||||||
|
|
||||||
# 获取用户的dict数据分页器
|
# 获取用户的dict数据分页器
|
||||||
def get_user_data_dict(page, limit, filters,deptId):
|
def get_user_data_dict(page, limit, filters, deptId):
|
||||||
user, count = get_user_data(page, limit, filters,deptId)
|
user, count = get_user_data(page, limit, filters, deptId)
|
||||||
data = model_to_dicts(Schema=UserSchema,model=user.items)
|
data = model_to_dicts(Schema=UserSchema, model=user.items)
|
||||||
return data, count
|
return data, count
|
||||||
|
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ def update_avatar(url):
|
|||||||
|
|
||||||
# 更新用户信息
|
# 更新用户信息
|
||||||
def update_user(id, username, realname, deptId):
|
def update_user(id, username, realname, deptId):
|
||||||
user = User.query.filter_by(id=id).update({'username': username, 'realname': realname,'dept_id':deptId})
|
user = User.query.filter_by(id=id).update({'username': username, 'realname': realname, 'dept_id': deptId})
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
from applications.models import db
|
from applications.extensions import db
|
||||||
from applications.models.admin_log import AdminLog
|
from applications.models import AdminLog
|
||||||
|
|
||||||
|
|
||||||
def login_log(request,uid, is_access):
|
def login_log(request, uid, is_access):
|
||||||
info = {
|
info = {
|
||||||
'method': request.method,
|
'method': request.method,
|
||||||
'url': request.path,
|
'url': request.path,
|
||||||
@@ -22,7 +22,7 @@ def login_log(request,uid, is_access):
|
|||||||
desc=info.get('desc'),
|
desc=info.get('desc'),
|
||||||
uid=info.get('uid'),
|
uid=info.get('uid'),
|
||||||
method=info.get('method'),
|
method=info.get('method'),
|
||||||
success = info.get('success')
|
success=info.get('success')
|
||||||
)
|
)
|
||||||
db.session.add(log)
|
db.session.add(log)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
@@ -38,7 +38,7 @@ def admin_log(request, is_access):
|
|||||||
'user_agent': request.headers.get('User-Agent'),
|
'user_agent': request.headers.get('User-Agent'),
|
||||||
'desc': str(dict(request.values)),
|
'desc': str(dict(request.values)),
|
||||||
'uid': current_user.id,
|
'uid': current_user.id,
|
||||||
'success':int(is_access)
|
'success': int(is_access)
|
||||||
|
|
||||||
}
|
}
|
||||||
log = AdminLog(
|
log = AdminLog(
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#
|
||||||
|
MYSQL_HOST = '127.0.0.1'
|
||||||
|
MYSQL_PORT = '3306'
|
||||||
|
MYSQL_DATABASE = 'PearAdminFlask'
|
||||||
|
MYSQL_USERNAME = 'root'
|
||||||
|
MYSQL_PASSWORD = 'root'
|
||||||
|
|
||||||
|
MYSQL_DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,
|
||||||
|
password=PASSWORD,
|
||||||
|
host=HOST,
|
||||||
|
port=PORT,
|
||||||
|
db=DATABASE)
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URI = MYSQL_DB_URI
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = True
|
||||||
|
SQLALCHEMY_ECHO = False
|
||||||
|
SQLALCHEMY_POOL_RECYCLE = 8
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from captcha.image import ImageCaptcha
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
from random import choices
|
||||||
|
|
||||||
|
|
||||||
|
def gen_captcha(content='0123456789'):
|
||||||
|
""" 生成验证码 """
|
||||||
|
image = ImageCaptcha()
|
||||||
|
# 获取字符串
|
||||||
|
captcha_text = "".join(choices(content, k=4))
|
||||||
|
# 生成图像
|
||||||
|
captcha_image = Image.open(image.generate(captcha_text))
|
||||||
|
return captcha_text, captcha_image
|
||||||
@@ -1,38 +1,20 @@
|
|||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
|
|
||||||
'''
|
|
||||||
成功响应
|
|
||||||
|
|
||||||
默认值”成功“
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def success_api(msg: str = "成功"):
|
def success_api(msg: str = "成功"):
|
||||||
return jsonify(success=True, msg=msg)
|
""" 成功响应 默认值”成功“ """
|
||||||
|
return jsonify(success=True, message=msg)
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
失败响应
|
|
||||||
默认值“失败”
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def fail_api(msg: str = "失败"):
|
def fail_api(msg: str = "失败"):
|
||||||
return jsonify(success=False, msg=msg)
|
""" 失败响应 默认值“失败” """
|
||||||
|
return jsonify(success=False, message=msg)
|
||||||
'''
|
|
||||||
|
|
||||||
动态表格渲染响应
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def table_api(msg: str = "", count=0, data=None, limit=10):
|
def table_api(msg: str = "", count=0, data=None, limit=10):
|
||||||
|
""" 动态表格渲染响应 """
|
||||||
res = {
|
res = {
|
||||||
'msg': msg,
|
'message': msg,
|
||||||
'code': 0,
|
'code': 0,
|
||||||
'data': data,
|
'data': data,
|
||||||
'count': count,
|
'count': count,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
from flask import abort, request, jsonify, session
|
from flask import abort, request, jsonify, session
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
from applications.service.admin_log import admin_log
|
from applications.common.admin_log import admin_log
|
||||||
|
|
||||||
|
|
||||||
def authorize(power: str, log: bool = False):
|
def authorize(power: str, log: bool = False):
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# 数据库连接
|
|
||||||
HOST = '127.0.0.1'
|
|
||||||
PORT = '3306'
|
|
||||||
DATABASE = 'PearAdminFlask'
|
|
||||||
USERNAME = 'root'
|
|
||||||
PASSWORD = 'root'
|
|
||||||
|
|
||||||
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD, host=HOST,port=PORT, db=DATABASE)
|
|
||||||
|
|
||||||
SQLALCHEMY_DATABASE_URI = DB_URI
|
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = True
|
|
||||||
SQLALCHEMY_ECHO = False
|
|
||||||
SQLALCHEMY_POOL_RECYCLE=8
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .config import config
|
||||||
@@ -17,9 +17,6 @@ SYSTEM_PANEL_LINKS = [
|
|||||||
"href": "https://gitee.com/Jmysy/Pear-Admin-Layui"
|
"href": "https://gitee.com/Jmysy/Pear-Admin-Layui"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
# 密钥
|
|
||||||
# 密钥配置(flask session需要) 记得修改
|
|
||||||
SECRET_KEY = 'pear-admin-flask'
|
|
||||||
|
|
||||||
UPLOADED_PHOTOS_DEST = 'static/upload'
|
UPLOADED_PHOTOS_DEST = 'static/upload'
|
||||||
UPLOADED_FILES_ALLOW = ['gif', 'jpg']
|
UPLOADED_FILES_ALLOW = ['gif', 'jpg']
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class BaseConfig:
|
||||||
|
SECRET_KEY = os.getenv('SECRET_KEY', 'dev key')
|
||||||
|
|
||||||
|
# redis配置
|
||||||
|
REDIS_HOST = os.getenv('REDIS_HOST') or "127.0.0.1"
|
||||||
|
REDIS_PORT = int(os.getenv('REDIS_PORT') or 6379)
|
||||||
|
|
||||||
|
# mysql 配置
|
||||||
|
MYSQL_USERNAME = os.getenv('MYSQL_USERNAME') or "root"
|
||||||
|
MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD') or "123456"
|
||||||
|
MYSQL_HOST = os.getenv('MYSQL_HOST') or "127.0.0.1"
|
||||||
|
MYSQL_PORT = int(os.getenv('MYSQL_PORT') or 3306)
|
||||||
|
MYSQL_DATABASE = os.getenv('MYSQL_DATABASE') or "PearAdminFlask"
|
||||||
|
|
||||||
|
# mysql 数据库的配置信息
|
||||||
|
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}"
|
||||||
|
# 默认日志等级
|
||||||
|
LOG_LEVEL = logging.WARN
|
||||||
|
|
||||||
|
|
||||||
|
class TestingConfig(BaseConfig):
|
||||||
|
""" 测试配置 """
|
||||||
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:' # 内存数据库
|
||||||
|
|
||||||
|
|
||||||
|
class DevelopmentConfig(BaseConfig):
|
||||||
|
""" 开发配置 """
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = True
|
||||||
|
SQLALCHEMY_ECHO = False
|
||||||
|
|
||||||
|
|
||||||
|
class ProductionConfig(BaseConfig):
|
||||||
|
"""生成环境配置"""
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
SQLALCHEMY_ECHO = False
|
||||||
|
SQLALCHEMY_POOL_RECYCLE = 8
|
||||||
|
|
||||||
|
LOG_LEVEL = logging.ERROR
|
||||||
|
|
||||||
|
|
||||||
|
config = {
|
||||||
|
'development': DevelopmentConfig,
|
||||||
|
'testing': TestingConfig,
|
||||||
|
'production': ProductionConfig
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
from .init_sqlalchemy import db, ma, init_databases
|
||||||
|
from .init_login import init_login_manager
|
||||||
|
from .init_debug_tool import init_debug_tool
|
||||||
|
from .init_template_directives import init_template_directives
|
||||||
|
from .init_error_views import init_error_views
|
||||||
|
|
||||||
|
|
||||||
|
def init_plugs(app: Flask) -> None:
|
||||||
|
init_debug_tool(app)
|
||||||
|
init_login_manager(app)
|
||||||
|
init_databases(app)
|
||||||
|
init_template_directives(app)
|
||||||
|
init_error_views(app)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
from flask import Flask
|
||||||
from flask_debugtoolbar import DebugToolbarExtension
|
from flask_debugtoolbar import DebugToolbarExtension
|
||||||
|
|
||||||
|
|
||||||
def open_debug_tool(app):
|
def init_debug_tool(app: Flask):
|
||||||
toolbar = DebugToolbarExtension()
|
toolbar = DebugToolbarExtension()
|
||||||
toolbar.init_app(app)
|
toolbar.init_app(app)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
root_path = os.path.abspath(os.path.dirname(__file__)).split('applications')[0]
|
||||||
|
dot_env_path = os.path.join(root_path, '.env')
|
||||||
|
flask_env_path = os.path.join(root_path, '.flaskenv')
|
||||||
|
|
||||||
|
if os.path.exists(dot_env_path):
|
||||||
|
load_dotenv(dot_env_path)
|
||||||
|
|
||||||
|
if os.path.exists(flask_env_path):
|
||||||
|
load_dotenv(flask_env_path)
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
from flask import render_template
|
from flask import render_template
|
||||||
|
|
||||||
|
|
||||||
def init_error(app):
|
def init_error_views(app):
|
||||||
|
|
||||||
@app.errorhandler(403)
|
@app.errorhandler(403)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
return render_template('errors/403.html'), 403
|
return render_template('errors/403.html'), 403
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from flask_login import LoginManager
|
from flask_login import LoginManager
|
||||||
|
|
||||||
|
|
||||||
def init_flask_login(app):
|
def init_login_manager(app):
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
login_manager.init_app(app)
|
login_manager.init_app(app)
|
||||||
|
|
||||||
@@ -10,6 +10,6 @@ def init_flask_login(app):
|
|||||||
|
|
||||||
@login_manager.user_loader
|
@login_manager.user_loader
|
||||||
def load_user(user_id):
|
def load_user(user_id):
|
||||||
from applications.models.admin_user import User
|
from applications.models import User
|
||||||
user = User.query.get(int(user_id))
|
user = User.query.get(int(user_id))
|
||||||
return user
|
return user
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
from flask import Flask
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_marshmallow import Marshmallow
|
||||||
|
from marshmallow import fields
|
||||||
|
from marshmallow.validate import (
|
||||||
|
URL, Email, Range, Length, Equal, Regexp,
|
||||||
|
Predicate, NoneOf, OneOf, ContainsOnly
|
||||||
|
)
|
||||||
|
|
||||||
|
URL.default_message = '无效的链接'
|
||||||
|
Email.default_message = '无效的邮箱地址'
|
||||||
|
Range.message_min = '不能小于{min}'
|
||||||
|
Range.message_max = '不能小于{max}'
|
||||||
|
Range.message_all = '不能超过{min}和{max}这个范围'
|
||||||
|
Length.message_min = '长度不得小于{min}位'
|
||||||
|
Length.message_max = '长度不得大于{max}位'
|
||||||
|
Length.message_all = '长度不能超过{min}和{max}这个范围'
|
||||||
|
Length.message_equal = '长度必须等于{equal}位'
|
||||||
|
Equal.default_message = '必须等于{other}'
|
||||||
|
Regexp.default_message = '非法输入'
|
||||||
|
Predicate.default_message = '非法输入'
|
||||||
|
NoneOf.default_message = '非法输入'
|
||||||
|
OneOf.default_message = '无效的选择'
|
||||||
|
ContainsOnly.default_message = '一个或多个无效的选择'
|
||||||
|
|
||||||
|
fields.Field.default_error_messages = {
|
||||||
|
"required": "缺少必要数据",
|
||||||
|
"null": "数据不能为空",
|
||||||
|
"validator_failed": "非法数据",
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.Str.default_error_messages = {
|
||||||
|
'invalid': "不是合法文本"
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.Int.default_error_messages = {
|
||||||
|
"invalid": "不是合法整数"
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.Number.default_error_messages = {
|
||||||
|
"invalid": "不是合法数字"
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.Boolean.default_error_messages = {
|
||||||
|
"invalid": "不是合法布尔值"
|
||||||
|
}
|
||||||
|
|
||||||
|
db = SQLAlchemy()
|
||||||
|
ma = Marshmallow()
|
||||||
|
|
||||||
|
|
||||||
|
def init_databases(app: Flask):
|
||||||
|
db.init_app(app)
|
||||||
|
ma.init_app(app)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from flask import session
|
from flask import session
|
||||||
|
|
||||||
|
|
||||||
def init_template_global(app):
|
def init_template_directives(app):
|
||||||
@app.template_global()
|
@app.template_global()
|
||||||
def authorize(power):
|
def authorize(power):
|
||||||
return bool(power in session.get('permissions'))
|
return bool(power in session.get('permissions'))
|
||||||
@@ -1,47 +1,9 @@
|
|||||||
from flask_sqlalchemy import SQLAlchemy
|
from .admin_dept import Dept, DeptSchema
|
||||||
from flask_marshmallow import Marshmallow
|
from .admin_dict import DictType, DictData, DictTypeSchema, DictDataSchema
|
||||||
from marshmallow import fields
|
from .admin_log import AdminLog, LogSchema
|
||||||
from marshmallow.validate import (
|
from .admin_photo import Photo, PhotoSchema
|
||||||
URL, Email, Range, Length, Equal, Regexp,
|
from .admin_power import Power, PowerSchema, PowerSchema2
|
||||||
Predicate, NoneOf, OneOf, ContainsOnly
|
from .admin_role import Role, RoleSchema
|
||||||
)
|
from .admin_role_power import role_power
|
||||||
|
from .admin_user import User, UserSchema
|
||||||
URL.default_message = '无效的链接'
|
from .admin_user_role import user_role
|
||||||
Email.default_message = '无效的邮箱地址'
|
|
||||||
Range.message_min = '不能小于{min}'
|
|
||||||
Range.message_max = '不能小于{max}'
|
|
||||||
Range.message_all = '不能超过{min}和{max}这个范围'
|
|
||||||
Length.message_min = '长度不得小于{min}位'
|
|
||||||
Length.message_max = '长度不得大于{max}位'
|
|
||||||
Length.message_all = '长度不能超过{min}和{max}这个范围'
|
|
||||||
Length.message_equal = '长度必须等于{equal}位'
|
|
||||||
Equal.default_message = '必须等于{other}'
|
|
||||||
Regexp.default_message = '非法输入'
|
|
||||||
Predicate.default_message = '非法输入'
|
|
||||||
NoneOf.default_message = '非法输入'
|
|
||||||
OneOf.default_message = '无效的选择'
|
|
||||||
ContainsOnly.default_message = '一个或多个无效的选择'
|
|
||||||
|
|
||||||
fields.Field.default_error_messages = {
|
|
||||||
"required": "缺少必要数据",
|
|
||||||
"null": "数据不能为空",
|
|
||||||
"validator_failed": "非法数据",
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.Str.default_error_messages = {
|
|
||||||
'invalid': "不是合法文本"
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.Int.default_error_messages = {
|
|
||||||
"invalid": "不是合法整数"
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.Number.default_error_messages = {
|
|
||||||
"invalid": "不是合法数字"
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.Boolean.default_error_messages = {
|
|
||||||
"invalid": "不是合法布尔值"
|
|
||||||
}
|
|
||||||
db = SQLAlchemy()
|
|
||||||
ma = Marshmallow()
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from applications.models import db, ma
|
from applications.extensions import db, ma
|
||||||
from marshmallow import fields,validate
|
from marshmallow import fields, validate
|
||||||
|
|
||||||
|
|
||||||
class Dept(db.Model):
|
class Dept(db.Model):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from applications.models import db, ma
|
from applications.extensions import db, ma
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from applications.models import db, ma
|
from applications.extensions import db, ma
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from applications.models import db, ma
|
from applications.extensions import db, ma
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from applications.models import db, ma
|
from applications.extensions import db, ma
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
|
|
||||||
|
|
||||||
@@ -47,4 +47,3 @@ class PowerSchema2(ma.Schema): # 序列化类
|
|||||||
create_time = fields.DateTime()
|
create_time = fields.DateTime()
|
||||||
update_time = fields.DateTime()
|
update_time = fields.DateTime()
|
||||||
enable = fields.Integer()
|
enable = fields.Integer()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from applications.models import db, ma
|
from applications.extensions import db, ma
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
from applications.models import admin_role_power
|
|
||||||
|
|
||||||
|
|
||||||
class Role(db.Model):
|
class Role(db.Model):
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from applications.models import db
|
from applications.extensions import db
|
||||||
|
|
||||||
# 创建中间表
|
# 创建中间表
|
||||||
role_power = db.Table(
|
role_power = db.Table(
|
||||||
"admin_role_power", # 中间表名称
|
"admin_role_power", # 中间表名称
|
||||||
db.Column("id", db.Integer, primary_key=True, autoincrement=True, comment='标识'), # 主键
|
db.Column("id", db.Integer, primary_key=True, autoincrement=True, comment='标识'), # 主键
|
||||||
db.Column("power_id", db.Integer, db.ForeignKey("admin_power.id"), comment='用户编号'), # 属性 外键
|
db.Column("power_id", db.Integer, db.ForeignKey("admin_power.id"), comment='用户编号'), # 属性 外键
|
||||||
db.Column("role_id", db.Integer, db.ForeignKey("admin_role.id"), comment='角色编号'), # 属性 外键
|
db.Column("role_id", db.Integer, db.ForeignKey("admin_role.id"), comment='角色编号'), # 属性 外键
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from flask_login import UserMixin
|
from flask_login import UserMixin
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
from applications.models import db, ma
|
from applications.extensions import db, ma
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
from applications.models import admin_user_role
|
from applications.models import Dept
|
||||||
from applications.models.admin_dept import Dept
|
|
||||||
|
|
||||||
|
|
||||||
class User(db.Model, UserMixin):
|
class User(db.Model, UserMixin):
|
||||||
@@ -43,4 +42,3 @@ class UserSchema(ma.Schema):
|
|||||||
return Dept.query.filter_by(id=obj.dept_id).first().dept_name
|
return Dept.query.filter_by(id=obj.dept_id).first().dept_name
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from applications.models import db
|
from applications.extensions import db
|
||||||
|
|
||||||
# 创建中间表
|
# 创建中间表
|
||||||
user_role = db.Table(
|
user_role = db.Table(
|
||||||
"admin_user_role", # 中间表名称
|
"admin_user_role", # 中间表名称
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
from captcha.image import ImageCaptcha
|
|
||||||
from PIL import Image
|
|
||||||
import random
|
|
||||||
|
|
||||||
|
|
||||||
# 定义随机方法
|
|
||||||
def random_captcha():
|
|
||||||
# 定义一个容器
|
|
||||||
captcha_text = []
|
|
||||||
for i in range(4):
|
|
||||||
# 定义验证码字符
|
|
||||||
c = random.choice(['0', '1', '2', '4', '6', '8'])
|
|
||||||
captcha_text.append(c)
|
|
||||||
# 返回一个随机生成的字符串
|
|
||||||
return ''.join(captcha_text)
|
|
||||||
|
|
||||||
|
|
||||||
# 生成验证码方法
|
|
||||||
def gen_captcha():
|
|
||||||
# 定义图片对象
|
|
||||||
image = ImageCaptcha()
|
|
||||||
# 获取字符串
|
|
||||||
captcha_text = random_captcha()
|
|
||||||
# 生成图像
|
|
||||||
captcha_image = Image.open(image.generate(captcha_text))
|
|
||||||
return captcha_text, captcha_image
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import datetime
|
|
||||||
import json
|
|
||||||
|
|
||||||
import pymysql
|
|
||||||
from applications.config.database import HOST, USERNAME, PASSWORD, DATABASE, PORT
|
|
||||||
|
|
||||||
DB_CONFIG = {
|
|
||||||
"host": HOST,
|
|
||||||
"port": int(PORT),
|
|
||||||
"user": USERNAME,
|
|
||||||
"password": PASSWORD,
|
|
||||||
"db": DATABASE,
|
|
||||||
"charset": "utf8"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class SQLManager(object):
|
|
||||||
|
|
||||||
# 初始化实例方法
|
|
||||||
def __init__(self):
|
|
||||||
self.conn = None
|
|
||||||
self.cursor = None
|
|
||||||
self.connect()
|
|
||||||
|
|
||||||
# 连接数据库
|
|
||||||
def connect(self):
|
|
||||||
self.conn = pymysql.connect(
|
|
||||||
host=DB_CONFIG.get('host'),
|
|
||||||
port=DB_CONFIG.get('port'),
|
|
||||||
user=DB_CONFIG.get('user'),
|
|
||||||
passwd=DB_CONFIG.get('password'),
|
|
||||||
db=DB_CONFIG.get('db'),
|
|
||||||
)
|
|
||||||
self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
|
|
||||||
|
|
||||||
# 查询多条数据
|
|
||||||
|
|
||||||
def get_list(self, sql, args=None):
|
|
||||||
self.cursor.execute(sql, args)
|
|
||||||
result = self.cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
# 查询多条数据后关闭
|
|
||||||
def get_list_close(self, sql, args=None):
|
|
||||||
self.cursor.execute(sql, args)
|
|
||||||
result = self.cursor.fetchall()
|
|
||||||
self.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
# 查询单条数据
|
|
||||||
def get_one(self, sql, args=None):
|
|
||||||
self.cursor.execute(sql, args)
|
|
||||||
result = self.cursor.fetchone()
|
|
||||||
return result
|
|
||||||
|
|
||||||
# 查询单条数据后关闭
|
|
||||||
def get_one_close(self, sql, args=None):
|
|
||||||
self.cursor.execute(sql, args)
|
|
||||||
result = self.cursor.fetchone()
|
|
||||||
self.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
# 执行单条SQL语句
|
|
||||||
def moddify(self, sql, args=None):
|
|
||||||
self.cursor.execute(sql, args)
|
|
||||||
self.conn.commit()
|
|
||||||
|
|
||||||
# 执行多条SQL语句
|
|
||||||
def multi_modify(self, sql, args=None):
|
|
||||||
self.cursor.executemany(sql, args)
|
|
||||||
self.conn.commit()
|
|
||||||
|
|
||||||
# 创建单条记录的语句
|
|
||||||
def create(self, sql, args=None):
|
|
||||||
self.cursor.execute(sql, args)
|
|
||||||
self.conn.commit()
|
|
||||||
last_id = self.cursor.lastrowid
|
|
||||||
return last_id
|
|
||||||
|
|
||||||
# 关闭数据库cursor和连接
|
|
||||||
def close(self):
|
|
||||||
self.cursor.close()
|
|
||||||
self.conn.close()
|
|
||||||
|
|
||||||
# 进入with语句自动执行
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
# 退出with语句块自动执行
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
原生查询dict的datetime解析器
|
|
||||||
用法
|
|
||||||
json.dumps(dictxxx, cls=DateEncoder)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class DateEncoder(json.JSONEncoder):
|
|
||||||
def default(self, obj):
|
|
||||||
if isinstance(obj, datetime.datetime):
|
|
||||||
return obj.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
else:
|
|
||||||
return json.JSONEncoder.default(self, obj)
|
|
||||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 701 B After Width: | Height: | Size: 701 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 299 KiB After Width: | Height: | Size: 299 KiB |