133 lines
5.0 KiB
Python
133 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
数据库迁移脚本:将旧的上传路径迁移到新的存储结构
|
|
使用同步 SQLAlchemy 进行数据库操作
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add backend to path
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
from sqlalchemy import create_engine, select, text
|
|
from sqlalchemy.orm import sessionmaker
|
|
from app.config import get_settings
|
|
|
|
settings = get_settings()
|
|
|
|
# 创建同步引擎
|
|
engine = create_engine(settings.DATABASE_URL.replace('+aiosqlite', ''), echo=False)
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
|
|
|
|
def migrate_image_paths():
|
|
"""迁移 Image 表中的路径"""
|
|
session = SessionLocal()
|
|
try:
|
|
# 获取所有图片
|
|
result = session.execute(text("SELECT id, file_path, thumb_path FROM images"))
|
|
images = result.fetchall()
|
|
|
|
updated_count = 0
|
|
for img in images:
|
|
img_id = img[0]
|
|
old_file_path = img[1]
|
|
old_thumb_path = img[2]
|
|
|
|
new_file_path = old_file_path
|
|
new_thumb_path = old_thumb_path
|
|
|
|
# 迁移 file_path
|
|
if old_file_path and not old_file_path.startswith('/storage/'):
|
|
if old_file_path.startswith('/'):
|
|
# 旧格式: /filename.jpg -> /storage/admin/images/filename.jpg
|
|
new_file_path = f"/storage/admin/images{old_file_path}"
|
|
else:
|
|
# 如果没有前导斜杠,添加一个
|
|
new_file_path = f"/storage/admin/images/{old_file_path}"
|
|
|
|
# 迁移 thumb_path
|
|
if old_thumb_path and not old_thumb_path.startswith('/storage/'):
|
|
if old_thumb_path.startswith('/'):
|
|
# 旧格式: /thumbnails/filename.jpg -> /storage/admin/images/thumbnails/filename.jpg
|
|
if old_thumb_path.startswith('/thumbnails/'):
|
|
new_thumb_path = f"/storage/admin/images{old_thumb_path}"
|
|
else:
|
|
new_thumb_path = f"/storage/admin/images/thumbnails{old_thumb_path}"
|
|
else:
|
|
new_thumb_path = f"/storage/admin/images/thumbnails/{old_thumb_path}"
|
|
|
|
if old_file_path != new_file_path or old_thumb_path != new_thumb_path:
|
|
session.execute(
|
|
text("UPDATE images SET file_path = :fp, thumb_path = :tp WHERE id = :id"),
|
|
{"fp": new_file_path, "tp": new_thumb_path, "id": img_id}
|
|
)
|
|
print(f" Image {img_id}: {old_file_path} -> {new_file_path}")
|
|
if old_thumb_path != new_thumb_path:
|
|
print(f" Thumb: {old_thumb_path} -> {new_thumb_path}")
|
|
updated_count += 1
|
|
|
|
session.commit()
|
|
print(f"\n✅ 迁移了 {updated_count} 张图片的路径")
|
|
finally:
|
|
session.close()
|
|
|
|
|
|
def migrate_news_cover_images():
|
|
"""迁移 NewsPost 表中的封面图片路径"""
|
|
session = SessionLocal()
|
|
try:
|
|
# 获取所有新闻文章
|
|
result = session.execute(text("SELECT id, cover_image FROM news_posts"))
|
|
posts = result.fetchall()
|
|
|
|
updated_count = 0
|
|
for post in posts:
|
|
post_id = post[0]
|
|
old_cover_image = post[1]
|
|
|
|
new_cover_image = old_cover_image
|
|
|
|
# 迁移 cover_image
|
|
if old_cover_image and not old_cover_image.startswith('/storage/'):
|
|
if old_cover_image.startswith('/'):
|
|
if old_cover_image.startswith('/uploads/'):
|
|
# 已经是 /uploads/ 格式,迁移到新的 storage 路径
|
|
filename = old_cover_image.replace('/uploads/', '')
|
|
new_cover_image = f"/storage/admin/images/{filename}"
|
|
else:
|
|
# 旧格式: /filename.jpg -> /storage/admin/images/filename.jpg
|
|
new_cover_image = f"/storage/admin/images{old_cover_image}"
|
|
else:
|
|
new_cover_image = f"/storage/admin/images/{old_cover_image}"
|
|
|
|
if old_cover_image != new_cover_image:
|
|
session.execute(
|
|
text("UPDATE news_posts SET cover_image = :ci WHERE id = :id"),
|
|
{"ci": new_cover_image, "id": post_id}
|
|
)
|
|
print(f" Post {post_id}: {old_cover_image} -> {new_cover_image}")
|
|
updated_count += 1
|
|
|
|
session.commit()
|
|
print(f"\n✅ 迁移了 {updated_count} 篇新闻的封面图片路径")
|
|
finally:
|
|
session.close()
|
|
|
|
|
|
def main():
|
|
print("=" * 60)
|
|
print("开始数据库路径迁移...")
|
|
print("=" * 60)
|
|
|
|
migrate_image_paths()
|
|
migrate_news_cover_images()
|
|
|
|
print("\n" + "=" * 60)
|
|
print("✅ 数据库迁移完成!")
|
|
print("=" * 60)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|