有没有用 Python 写的论坛程序,支持从 Discuz 迁移数据?

目前比较感兴趣的是 Vanilla ,但不知道怎么迁移数据。。
有没有用 Python 写的论坛程序,支持从 Discuz 迁移数据?

13 回复

自己看下表结构直接转过去,跑几句 sql 的事。


有,FlaskBB 是一个不错的选择。它用 Python 的 Flask 框架开发,功能完整,社区活跃。虽然官方没有内置的 Discuz 迁移工具,但它的数据库结构清晰,我们可以写一个 Python 脚本来完成数据迁移。

核心思路是:连接 Discuz 的 MySQL 数据库,读取用户、版块、帖子等数据,然后按照 FlaskBB 的模型结构,通过 SQLAlchemy 写入到新数据库。

下面是一个概念性的迁移脚本框架,展示了主要的数据表转换逻辑。你需要根据实际的 Discuz 版本和表前缀修改数据库连接信息和字段映射。

import pymysql
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, ForeignKey, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import hashlib
import pytz

# 1. 数据库连接配置 (根据你的实际情况修改)
DZ_DB_CONFIG = {
    'host': 'localhost',
    'user': 'your_dz_user',
    'password': 'your_dz_password',
    'database': 'discuz_db',
    'charset': 'utf8mb4',
    'port': 3306,
    'table_prefix': 'pre_'  # Discuz 表前缀
}

FLASKBB_DB_URI = 'sqlite:///flaskbb.db'  # 或 'mysql+pymysql://...'

# 2. 连接数据库
dz_conn = pymysql.connect(**DZ_DB_CONFIG)
dz_cursor = dz_conn.cursor(pymysql.cursors.DictCursor)

# FlaskBB ORM 模型基类
Base = declarative_base()

# 3. 定义关键的 FlaskBB 模型 (这里只列核心字段)
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String(200), unique=True)
    email = Column(String(200), unique=True)
    password = Column(String(200))
    date_joined = Column(DateTime, default=datetime.utcnow)
    # ... 其他字段

class Category(Base):
    __tablename__ = 'categories'
    id = Column(Integer, primary_key=True)
    title = Column(String(255))
    description = Column(Text)

class Forum(Base):
    __tablename__ = 'forums'
    id = Column(Integer, primary_key=True)
    category_id = Column(Integer, ForeignKey('categories.id'))
    title = Column(String(255))
    description = Column(Text)

class Topic(Base):
    __tablename__ = 'topics'
    id = Column(Integer, primary_key=True)
    forum_id = Column(Integer, ForeignKey('forums.id'))
    user_id = Column(Integer, ForeignKey('users.id'))
    title = Column(String(255))
    date_created = Column(DateTime, default=datetime.utcnow)
    # ... 其他字段

class Post(Base):
    __tablename__ = 'posts'
    id = Column(Integer, primary_key=True)
    topic_id = Column(Integer, ForeignKey('topics.id'))
    user_id = Column(Integer, ForeignKey('users.id'))
    content = Column(Text)
    date_created = Column(DateTime, default=datetime.utcnow)

# 4. 创建 FlaskBB 数据库表
engine = create_engine(FLASKBB_DB_URI)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

# 5. 数据迁移函数
def migrate_users():
    """迁移用户数据"""
    table = f"{DZ_DB_CONFIG['table_prefix']}common_member"
    dz_cursor.execute(f"SELECT uid, username, email, password, regdate FROM {table}")
    for row in dz_cursor.fetchall():
        # Discuz 密码需要特殊处理,这里假设使用默认的 md5 加密
        # 实际可能需要根据 Discuz 的加密方式调整
        user = User(
            id=row['uid'],
            username=row['username'],
            email=row['email'],
            password=row['password'],  # 注意:可能需要重新加密或使用兼容方式
            date_joined=datetime.fromtimestamp(row['regdate'], tz=pytz.UTC)
        )
        session.merge(user)  # 使用 merge 避免 ID 冲突
    session.commit()
    print("用户数据迁移完成")

def migrate_forums():
    """迁移版块数据"""
    # 先迁移分类
    dz_cursor.execute(f"SELECT fid, name, description FROM {DZ_DB_CONFIG['table_prefix']}forum_forum WHERE type='group'")
    for row in dz_cursor.fetchall():
        category = Category(id=row['fid'], title=row['name'], description=row['description'])
        session.merge(category)
    
    # 再迁移论坛版块
    dz_cursor.execute(f"SELECT fid, fup, name, description FROM {DZ_DB_CONFIG['table_prefix']}forum_forum WHERE type='forum'")
    for row in dz_cursor.fetchall():
        forum = Forum(id=row['fid'], category_id=row['fup'], title=row['name'], description=row['description'])
        session.merge(forum)
    session.commit()
    print("版块数据迁移完成")

def migrate_topics_and_posts():
    """迁移主题和帖子"""
    # 迁移主题
    dz_cursor.execute(f"""
        SELECT tid, fid, authorid, subject, dateline 
        FROM {DZ_DB_CONFIG['table_prefix']}forum_thread 
        WHERE displayorder>=0
    """)
    for row in dz_cursor.fetchall():
        topic = Topic(
            id=row['tid'],
            forum_id=row['fid'],
            user_id=row['authorid'],
            title=row['subject'],
            date_created=datetime.fromtimestamp(row['dateline'], tz=pytz.UTC)
        )
        session.merge(topic)
    
    # 迁移帖子
    dz_cursor.execute(f"""
        SELECT pid, tid, authorid, message, dateline 
        FROM {DZ_DB_CONFIG['table_prefix']}forum_post 
        WHERE invisible=0 AND first=1
    """)
    for row in dz_cursor.fetchall():
        post = Post(
            id=row['pid'],
            topic_id=row['tid'],
            user_id=row['authorid'],
            content=row['message'],
            date_created=datetime.fromtimestamp(row['dateline'], tz=pytz.UTC)
        )
        session.merge(post)
    session.commit()
    print("主题和帖子迁移完成")

# 6. 执行迁移
if __name__ == '__main__':
    try:
        print("开始迁移数据...")
        migrate_users()
        migrate_forums()
        migrate_topics_and_posts()
        print("所有数据迁移完成!")
    except Exception as e:
        session.rollback()
        print(f"迁移过程中出现错误: {e}")
    finally:
        dz_cursor.close()
        dz_conn.close()
        session.close()

重要提醒:

  1. 密码问题:Discuz 的密码加密方式可能与 FlaskBB 不兼容。脚本中直接复制了密码字段,这很可能导致用户无法登录。你需要研究两者的加密方式,并在迁移时进行转换,或者引导用户在首次登录时重置密码。
  2. 数据完整性:这个脚本只迁移了最核心的用户、版块、主题和帖子数据。像用户组权限、私人消息、附件、点赞等数据需要你根据业务需求额外处理。
  3. 测试务必先在测试环境完整运行,验证数据正确性和完整性后,再对生产数据进行操作。
  4. 备份:操作前,备份好 Discuz 和 FlaskBB 的数据库。

总结建议:用 FlaskBB 加自定义迁移脚本是目前最可行的方案。

楼主你要是搞定了记得写个教程

这个不是很简单吧,需要比较熟悉 discuz

就是一个数据库换个程序读写而已吧?很难吗

我搜了一下,不是 Python 写的吧

discuz 那么多复杂的业务逻辑,只读个 sql 应该不行吧

楼上说说都简单的。真要转起来,一堆麻烦事呢。

DZ 那么多的表,没看懂估计还不好转

友情提醒楼上们: Discuz 的表有三百多个

DZ 里面巨多表逻辑很复杂,几句 sql 还真搞不定




关键是目标数据库简单。

楼主成功了也分享一下教程, mark 一下

回到顶部