Commit 95a2e798 by luoqi

feat:数据库迁移

parent a8d60f47
Pipeline #3226 passed with stage
in 21 seconds
...@@ -39,6 +39,9 @@ Thumbs.db ...@@ -39,6 +39,9 @@ Thumbs.db
# Database files # Database files
*.db *.db
# Database backups
database/backups/
# Logs # Logs
*.log *.log
......
"""test
Revision ID: ef36020a1ab8
Revises: 9bd0518d29b3
Create Date: 2025-09-10 10:06:10.751945
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = 'ef36020a1ab8'
down_revision = '9bd0518d29b3'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('clinics', schema=None) as batch_op:
batch_op.alter_column('created_at',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
batch_op.alter_column('updated_at',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='更新时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
with op.batch_alter_table('operation_logs', schema=None) as batch_op:
batch_op.alter_column('created_at',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
with op.batch_alter_table('patients', schema=None) as batch_op:
batch_op.alter_column('clinic_id',
existing_type=mysql.INTEGER(),
comment='诊所ID',
existing_comment='ID',
existing_nullable=True)
batch_op.alter_column('created_at',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
batch_op.alter_column('updated_at',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='更新时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.alter_column('created_at',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
batch_op.alter_column('updated_at',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='更新时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
batch_op.alter_column('last_login',
existing_type=mysql.TIMESTAMP(),
type_=sa.DateTime(),
existing_comment='最后登录时间',
existing_nullable=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.alter_column('last_login',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='最后登录时间',
existing_nullable=True)
batch_op.alter_column('updated_at',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='更新时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
batch_op.alter_column('created_at',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
with op.batch_alter_table('patients', schema=None) as batch_op:
batch_op.alter_column('updated_at',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='更新时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
batch_op.alter_column('created_at',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
batch_op.alter_column('clinic_id',
existing_type=mysql.INTEGER(),
comment='ID',
existing_comment='诊所ID',
existing_nullable=True)
with op.batch_alter_table('operation_logs', schema=None) as batch_op:
batch_op.alter_column('created_at',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
with op.batch_alter_table('clinics', schema=None) as batch_op:
batch_op.alter_column('updated_at',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='更新时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
batch_op.alter_column('created_at',
existing_type=sa.DateTime(),
type_=mysql.TIMESTAMP(),
existing_comment='创建时间',
existing_nullable=True,
existing_server_default=sa.text('CURRENT_TIMESTAMP'))
# ### end Alembic commands ###
...@@ -9,6 +9,7 @@ import os ...@@ -9,6 +9,7 @@ import os
import sys import sys
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from datetime import datetime
# 添加项目根目录到Python路径 # 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent.parent project_root = Path(__file__).parent.parent.parent
...@@ -80,6 +81,24 @@ def generate_migration(message="Auto migration"): ...@@ -80,6 +81,24 @@ def generate_migration(message="Auto migration"):
os.environ['FLASK_APP'] = 'app.py' os.environ['FLASK_APP'] = 'app.py'
return run_command(f'flask db migrate -m "{message}"', '生成迁移文件') return run_command(f'flask db migrate -m "{message}"', '生成迁移文件')
def backup_database():
"""备份数据库到database/backups目录"""
print("📦 备份数据库...")
# 确保备份目录存在
backup_dir = project_root / "database" / "backups"
backup_dir.mkdir(exist_ok=True)
# 生成带时间戳的备份文件名
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = backup_dir / f"backup_before_migration_{timestamp}.sql"
# 构建备份命令
backup_command = f"docker exec patient_callback_mysql mysqldump -u callback_user -pdev_password_123 callback_system > {backup_file}"
print(f"📁 备份文件: {backup_file}")
return run_command(backup_command, f"备份数据库到 {backup_file.name}")
def upgrade_database(): def upgrade_database():
"""执行数据库迁移""" """执行数据库迁移"""
print("📋 执行数据库迁移...") print("📋 执行数据库迁移...")
...@@ -109,6 +128,18 @@ def check_alembic_version_table(): ...@@ -109,6 +128,18 @@ def check_alembic_version_table():
print(f"⚠️ 检查alembic_version表失败: {e}") print(f"⚠️ 检查alembic_version表失败: {e}")
return False return False
def backup_only():
"""仅执行数据库备份"""
print("🚀 数据库备份工具启动")
print(f"📍 项目根目录: {project_root}")
if backup_database():
print("🎉 数据库备份完成")
return True
else:
print("❌ 数据库备份失败")
return False
def main(): def main():
"""主函数 - 完整的迁移流程""" """主函数 - 完整的迁移流程"""
print("🚀 数据库迁移管理器启动") print("🚀 数据库迁移管理器启动")
...@@ -137,6 +168,13 @@ def main(): ...@@ -137,6 +168,13 @@ def main():
# 步骤4: 获取当前状态 # 步骤4: 获取当前状态
get_current_revision() get_current_revision()
# 步骤4.5: 备份数据库(在迁移前)
print("🔄 迁移前备份数据库...")
if not backup_database():
print("❌ 数据库备份失败,取消迁移")
return False
print("✅ 数据库备份完成")
# 步骤5: 执行迁移 # 步骤5: 执行迁移
if not upgrade_database(): if not upgrade_database():
print("❌ 数据库迁移失败") print("❌ 数据库迁移失败")
...@@ -146,5 +184,9 @@ def main(): ...@@ -146,5 +184,9 @@ def main():
return True return True
if __name__ == '__main__': if __name__ == '__main__':
success = main() # 检查命令行参数
if len(sys.argv) > 1 and sys.argv[1] == 'backup':
success = backup_only()
else:
success = main()
sys.exit(0 if success else 1) sys.exit(0 if success else 1)
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