344 lines
10 KiB
Python
344 lines
10 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
MySQL数据库快速配置脚本
|
|||
|
|
|
|||
|
|
此脚本将帮助您:
|
|||
|
|
1. 检查MySQL配置
|
|||
|
|
2. 创建数据库(如果不存在)
|
|||
|
|
3. 测试数据库连接
|
|||
|
|
4. 初始化表结构
|
|||
|
|
5. 创建默认超级管理员(如果需要)
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|||
|
|
|
|||
|
|
from app import create_app, db
|
|||
|
|
from app.models import Admin
|
|||
|
|
from werkzeug.security import generate_password_hash
|
|||
|
|
|
|||
|
|
def parse_database_url(url):
|
|||
|
|
"""解析数据库URL"""
|
|||
|
|
# 格式: mysql+pymysql://user:password@host:port/database
|
|||
|
|
try:
|
|||
|
|
# 移除mysql+pymysql://前缀
|
|||
|
|
url = url.replace('mysql+pymysql://', '')
|
|||
|
|
|
|||
|
|
# 找到@符号前的用户名密码
|
|||
|
|
at_index = url.index('@')
|
|||
|
|
user_pass = url[:at_index]
|
|||
|
|
url = url[at_index + 1:]
|
|||
|
|
|
|||
|
|
# 分割用户名和密码
|
|||
|
|
user, password = user_pass.split(':', 1)
|
|||
|
|
|
|||
|
|
# 找到数据库名
|
|||
|
|
if '/' in url:
|
|||
|
|
host_port, database = url.split('/', 1)
|
|||
|
|
# 提取端口
|
|||
|
|
if ':' in host_port:
|
|||
|
|
host, port = host_port.split(':', 1)
|
|||
|
|
else:
|
|||
|
|
host = host_port
|
|||
|
|
port = '3306'
|
|||
|
|
else:
|
|||
|
|
raise ValueError("URL格式不正确")
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'user': user,
|
|||
|
|
'password': password,
|
|||
|
|
'host': host,
|
|||
|
|
'port': port,
|
|||
|
|
'database': database
|
|||
|
|
}
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 无法解析数据库URL: {e}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def check_mysql_dependencies():
|
|||
|
|
"""检查MySQL依赖"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("1. 检查MySQL依赖")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
import pymysql
|
|||
|
|
print(f"✅ PyMySQL已安装 (版本: {pymysql.__version__})")
|
|||
|
|
return True
|
|||
|
|
except ImportError:
|
|||
|
|
print("❌ PyMySQL未安装")
|
|||
|
|
print("请运行: pip install PyMySQL")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def check_dotenv():
|
|||
|
|
"""检查.env文件加载"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("2. 检查.env文件")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
env_file = '.env'
|
|||
|
|
if os.path.exists(env_file):
|
|||
|
|
print(f"✅ 找到.env文件: {os.path.abspath(env_file)}")
|
|||
|
|
|
|||
|
|
# 读取DATABASE_URL
|
|||
|
|
with open(env_file, 'r', encoding='utf-8') as f:
|
|||
|
|
for line in f:
|
|||
|
|
if line.startswith('DATABASE_URL='):
|
|||
|
|
url = line.split('=', 1)[1].strip()
|
|||
|
|
print(f"✅ DATABASE_URL已配置: {url}")
|
|||
|
|
return url
|
|||
|
|
print("⚠️ .env文件中未找到DATABASE_URL")
|
|||
|
|
return None
|
|||
|
|
else:
|
|||
|
|
print(f"❌ 未找到.env文件: {os.path.abspath(env_file)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def test_database_connection():
|
|||
|
|
"""测试数据库连接"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("3. 测试数据库连接")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
app = create_app()
|
|||
|
|
|
|||
|
|
with app.app_context():
|
|||
|
|
try:
|
|||
|
|
# 测试连接
|
|||
|
|
db.create_all()
|
|||
|
|
print("✅ 数据库连接成功!")
|
|||
|
|
return True
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 数据库连接失败: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def create_database():
|
|||
|
|
"""创建数据库(如果不存在)"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("4. 创建数据库")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
# 从.env文件获取数据库配置
|
|||
|
|
env_file = '.env'
|
|||
|
|
if not os.path.exists(env_file):
|
|||
|
|
print("❌ .env文件不存在")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
with open(env_file, 'r', encoding='utf-8') as f:
|
|||
|
|
for line in f:
|
|||
|
|
if line.startswith('DATABASE_URL='):
|
|||
|
|
db_url = line.split('=', 1)[1].strip()
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if not db_url:
|
|||
|
|
print("❌ 未找到DATABASE_URL配置")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 解析URL
|
|||
|
|
db_config = parse_database_url(db_url)
|
|||
|
|
if not db_config:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
print(f"数据库信息:")
|
|||
|
|
print(f" 主机: {db_config['host']}")
|
|||
|
|
print(f" 端口: {db_config['port']}")
|
|||
|
|
print(f" 数据库: {db_config['database']}")
|
|||
|
|
print(f" 用户: {db_config['user']}")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
import pymysql
|
|||
|
|
|
|||
|
|
# 连接到MySQL服务器(不指定数据库)
|
|||
|
|
connection = pymysql.connect(
|
|||
|
|
host=db_config['host'],
|
|||
|
|
port=int(db_config['port']),
|
|||
|
|
user=db_config['user'],
|
|||
|
|
password=db_config['password'],
|
|||
|
|
charset='utf8mb4'
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
with connection.cursor() as cursor:
|
|||
|
|
# 检查数据库是否存在
|
|||
|
|
cursor.execute(f"SHOW DATABASES LIKE '{db_config['database']}'")
|
|||
|
|
result = cursor.fetchone()
|
|||
|
|
|
|||
|
|
if not result:
|
|||
|
|
print(f"📦 正在创建数据库 '{db_config['database']}'...")
|
|||
|
|
cursor.execute(
|
|||
|
|
f"CREATE DATABASE {db_config['database']} "
|
|||
|
|
"CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
|
|||
|
|
)
|
|||
|
|
print(f"✅ 数据库 '{db_config['database']}' 创建成功")
|
|||
|
|
else:
|
|||
|
|
print(f"✅ 数据库 '{db_config['database']}' 已存在")
|
|||
|
|
|
|||
|
|
connection.close()
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
except ImportError:
|
|||
|
|
print("❌ PyMySQL未安装,请运行: pip install PyMySQL")
|
|||
|
|
return False
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 创建数据库失败: {e}")
|
|||
|
|
print("请手动创建数据库,或检查MySQL服务是否运行")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def init_database():
|
|||
|
|
"""初始化数据库表"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("5. 初始化数据库表")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
app = create_app()
|
|||
|
|
|
|||
|
|
with app.app_context():
|
|||
|
|
try:
|
|||
|
|
# 检查admin表
|
|||
|
|
admin_columns = [c.name for c in Admin.__table__.columns]
|
|||
|
|
print(f"📋 Admin表字段: {', '.join(admin_columns)}")
|
|||
|
|
|
|||
|
|
# 检查新字段
|
|||
|
|
if 'is_deleted' not in admin_columns:
|
|||
|
|
print("⚠️ 缺少软删除字段,正在添加...")
|
|||
|
|
db.session.execute("ALTER TABLE admin ADD COLUMN is_deleted INT NOT NULL DEFAULT 0")
|
|||
|
|
db.session.execute("ALTER TABLE admin ADD COLUMN delete_time DATETIME NULL")
|
|||
|
|
db.session.execute("CREATE INDEX ix_admin_is_deleted ON admin(is_deleted)")
|
|||
|
|
db.session.commit()
|
|||
|
|
print("✅ 软删除字段添加成功")
|
|||
|
|
|
|||
|
|
# 检查audit_log表
|
|||
|
|
try:
|
|||
|
|
from app.models import AuditLog
|
|||
|
|
AuditLog.query.count()
|
|||
|
|
print("✅ audit_log表存在")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"⚠️ audit_log表不存在,正在创建...")
|
|||
|
|
db.session.execute("""
|
|||
|
|
CREATE TABLE audit_log (
|
|||
|
|
log_id INT AUTO_INCREMENT PRIMARY KEY,
|
|||
|
|
admin_id INT NOT NULL,
|
|||
|
|
action VARCHAR(32) NOT NULL,
|
|||
|
|
target_type VARCHAR(32) NOT NULL,
|
|||
|
|
target_id INT NULL,
|
|||
|
|
details TEXT NULL,
|
|||
|
|
ip_address VARCHAR(32) NULL,
|
|||
|
|
user_agent VARCHAR(256) NULL,
|
|||
|
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (admin_id) REFERENCES admin(admin_id)
|
|||
|
|
)
|
|||
|
|
""")
|
|||
|
|
db.session.execute("CREATE INDEX ix_audit_log_admin_id ON audit_log(admin_id)")
|
|||
|
|
db.session.execute("CREATE INDEX ix_audit_log_action ON audit_log(action)")
|
|||
|
|
db.session.execute("CREATE INDEX ix_audit_log_create_time ON audit_log(create_time)")
|
|||
|
|
db.session.commit()
|
|||
|
|
print("✅ audit_log表创建成功")
|
|||
|
|
|
|||
|
|
print("✅ 数据库表初始化成功")
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
db.session.rollback()
|
|||
|
|
print(f"❌ 数据库表初始化失败: {e}")
|
|||
|
|
import traceback
|
|||
|
|
traceback.print_exc()
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def create_default_admin():
|
|||
|
|
"""创建默认超级管理员(如果需要)"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("6. 创建默认超级管理员")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
app = create_app()
|
|||
|
|
|
|||
|
|
with app.app_context():
|
|||
|
|
try:
|
|||
|
|
# 检查是否已有超级管理员
|
|||
|
|
super_admin = Admin.query.filter_by(role=1, status=1, is_deleted=0).first()
|
|||
|
|
|
|||
|
|
if super_admin:
|
|||
|
|
print(f"✅ 已存在超级管理员: {super_admin.username}")
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
print("📝 没有超级管理员,创建默认账号...")
|
|||
|
|
print(" 用户名: admin")
|
|||
|
|
print(" 密码: admin123456")
|
|||
|
|
print(" ⚠️ 登录后请立即修改密码!")
|
|||
|
|
|
|||
|
|
admin = Admin(
|
|||
|
|
username='admin',
|
|||
|
|
email='admin@example.com',
|
|||
|
|
role=1,
|
|||
|
|
status=1
|
|||
|
|
)
|
|||
|
|
admin.set_password('admin123456')
|
|||
|
|
|
|||
|
|
db.session.add(admin)
|
|||
|
|
db.session.commit()
|
|||
|
|
|
|||
|
|
print("✅ 默认超级管理员创建成功")
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
db.session.rollback()
|
|||
|
|
print(f"❌ 创建超级管理员失败: {e}")
|
|||
|
|
import traceback
|
|||
|
|
traceback.print_exc()
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""主函数"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("🚀 MySQL数据库快速配置工具")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
success = True
|
|||
|
|
|
|||
|
|
# 1. 检查依赖
|
|||
|
|
if not check_mysql_dependencies():
|
|||
|
|
print("\n⚠️ 请先安装PyMySQL: pip install PyMySQL")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
# 2. 检查.env文件
|
|||
|
|
db_url = check_dotenv()
|
|||
|
|
if not db_url:
|
|||
|
|
print("\n⚠️ 请配置.env文件中的DATABASE_URL")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
# 3. 创建数据库
|
|||
|
|
if not create_database():
|
|||
|
|
success = False
|
|||
|
|
|
|||
|
|
# 4. 测试连接
|
|||
|
|
if success and not test_database_connection():
|
|||
|
|
success = False
|
|||
|
|
|
|||
|
|
# 5. 初始化表
|
|||
|
|
if success and not init_database():
|
|||
|
|
success = False
|
|||
|
|
|
|||
|
|
# 6. 创建默认管理员
|
|||
|
|
if success and not create_default_admin():
|
|||
|
|
success = False
|
|||
|
|
|
|||
|
|
# 总结
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
if success:
|
|||
|
|
print("🎉 MySQL配置完成!")
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("\n✅ 现在可以启动应用:")
|
|||
|
|
print(" python run.py")
|
|||
|
|
print("\n📖 默认管理员登录信息:")
|
|||
|
|
print(" 用户名: admin")
|
|||
|
|
print(" 密码: admin123456")
|
|||
|
|
print(" ⚠️ 登录后请立即修改密码!")
|
|||
|
|
return 0
|
|||
|
|
else:
|
|||
|
|
print("❌ 配置未完成,请查看错误信息")
|
|||
|
|
print("=" * 60)
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
sys.exit(main())
|