#!/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()