Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
customer-recall
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tools
customer-recall
Commits
95a2e798
Commit
95a2e798
authored
Sep 10, 2025
by
luoqi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:数据库迁移
parent
a8d60f47
Pipeline
#3226
passed with stage
in 21 seconds
Changes
3
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
191 additions
and
0 deletions
+191
-0
.gitignore
+3
-0
database/migrations/versions/ef36020a1ab8_test.py
+146
-0
database/scripts/migration_manager.py
+42
-0
No files found.
.gitignore
View file @
95a2e798
...
@@ -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
...
...
database/migrations/versions/ef36020a1ab8_test.py
0 → 100644
View file @
95a2e798
"""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 ###
database/scripts/migration_manager.py
View file @
95a2e798
...
@@ -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__'
:
# 检查命令行参数
if
len
(
sys
.
argv
)
>
1
and
sys
.
argv
[
1
]
==
'backup'
:
success
=
backup_only
()
else
:
success
=
main
()
success
=
main
()
sys
.
exit
(
0
if
success
else
1
)
sys
.
exit
(
0
if
success
else
1
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment