从 Wagtail 迁移到 Astro(二):迁移的几个阶段
· 约 12 分钟阅读
Last updated on

从 Wagtail 迁移到 Astro(二):迁移的几个阶段

作者: Alex Xiang


本文是「Wagtail 迁移 Astro」系列的第二篇,说明迁移工作拆成的几个阶段,以及每个阶段要完成的事情。

一、整体阶段划分

迁移可以拆成四个主要阶段,顺序建议如下:

阶段 1:数据与资源同步 → 阶段 2:内容转换与导入 → 阶段 3:站点结构与脚本化 → 阶段 4:验证与切换

下面按阶段说明。


二、阶段 1:数据与资源同步

目标:把线上 Wagtail 的「数据」和「媒体资源」拿到本地,且可重复执行(便于后续增量更新)。

2.1 需要同步的内容

  • 数据库:Wagtail 使用的 SQLite(如 zicodedb),包含文章、分类、标签、专栏、StreamField 等。
  • 媒体文件:上传的图片等,通常位于 media/original_images/ 或类似路径。
  • 必要代码/配置:若需本地用 Django 跑一遍导出逻辑,可同步 manage.pyrequirements.txt、相关 app 与模板。

2.2 同步方式建议

  • 使用 SSH + 远程命令(如 scprsync)从服务器拉取:
    • 数据库文件整份拷贝到本地 legacy-wagtail/ 或类似目录。
    • 媒体目录按需 rsync,避免重复拉取大文件。
  • 在项目里写一个 同步脚本(如 scripts/sync_legacy.py),用配置项记录主机、路径、本地目录,以后一键执行,便于增量更新。

同步完成后,本地应具备:一份可读的 SQLite、一份与线上一致的媒体文件、以及(如需要)可运行的 Wagtail 项目副本。


三、阶段 2:内容转换与导入

目标:把 Wagtail 里的文章变成 Astro 的 Markdown + frontmatter,并处理好图片路径。

3.1 内容模型对应关系

Wagtail 概念Astro 对应
文章标题、摘要、正文title, description, Markdown body
发布时间、更新时间pubDate, updatedDate
分类、专栏category, column(frontmatter 字符串)
标签tags(frontmatter 字符串数组)
作者authors(frontmatter 字符串数组)
头图/特色图heroImage(相对路径或 URL)
StreamField 块解析为 Markdown:段落、标题、列表、代码块、图片块等

3.2 正文转换要点

Wagtail 的 StreamField 存的是 JSON 数组,每个元素有 typevalue。常见块类型与转换方式如下:

块类型典型 value转为 Markdown 的方式
paragraph{ "text": "..." }直接输出为一段,前后空行
markdown{ "source": "..." }原样输出 source,必要时包在代码块外
heading{ "text": "标题", "level": 2 }输出 ## 标题(按 level 写 # 个数)
image{ "image": id 或 path }查媒体表得到路径,输出 ![](/uploads/...)
code{ "language": "python", "code": "..." }输出 ```language\n...\n```
list{ "items": [...] }遍历 items 输出 - item 或有序列表

注意:图片块需要根据 Wagtail 的 media 表或文件路径解析出实际文件名,并统一写成站内路径(如 /uploads/original_images/xxx.png),导入时把文件拷贝到 public/uploads/original_images/。若原有内容已是 Markdown 块,可尽量保留原样,只做换行与块类型包装上的统一;避免对 Markdown 做二次转义导致代码块或链接错乱。

3.3 导入脚本

  • 写一个 导入脚本(如 scripts/import_wagtail.py):
    • 连接本地 SQLite,读取文章表与相关字段。
    • 按上述规则生成 frontmatter + Markdown 正文。
    • 将每篇文章写入 src/content/blog/imported/xxx.md
    • 可选:同时拷贝用到的图片到 public/uploads/original_images/
  • 建议为每篇导入文章保留 legacyId(Wagtail 主键),便于以后对账或重跑部分导入。

完成本阶段后,应能在 Astro 里通过 getCollection('blog') 看到全部历史文章,且排版、链接、图片正常。

常见问题

  • 图片 404:检查导入脚本里图片目标路径是否与 frontmatter 中的 heroImage、正文里的 ![](...) 一致,且文件确实拷贝到了 public/ 下。
  • 中文 slug 乱码:Astro 路由若用中文,需统一用 encodeURIComponent 或自建 slug(如拼音),并在导航、面包屑里一致使用,避免一半编码一半不编码。

四、阶段 3:站点结构与脚本化

目标:确定 URL 结构、导航、专栏/分类/标签页,并把「同步 + 导入」固化为一键流程。

4.1 URL 设计

  • 文章页:/blog/<slug>/,与 Wagtail 的 slug 或自定义 slug 一致,便于做 301 重定向(若需要)。
  • 分类 / 专栏 / 标签:/blog/category/<name>//blog/column/<name>//blog/tag/<name>/,对中文名做 encodeURIComponent 或统一 slug 规则。

4.2 导航与数据

  • 在 Astro 中通过 getCollection 计算分类、专栏、标签列表,供 Header、Footer、侧栏使用。
  • 专栏名、分类名与 Wagtail 保持一致,这样内部链接和读者习惯都不会乱。

4.3 脚本化

  • sync:从服务器拉取最新数据库与媒体(如 python scripts/sync_legacy.py)。
  • import:读取本地 SQLite,覆盖或增量写入 src/content/blog/imported/(注意不要误删手写的新文章)。
  • 可选:在 CI 或本地 Makefile 中串联 sync → import → astro build,实现「从旧站拉数据 → 重新导入 → 构建」一条龙。

五、阶段 4:验证与切换

目标:确认迁移结果正确,再切换线上流量或与现有站点并存。

5.1 内容校验

  • 文章数量、标题、日期与 Wagtail 后台或导出列表一致。
  • 抽检若干篇文章:正文、代码块、图片、内链是否正常。
  • 分类、专栏、标签列表是否完整,链接是否可访问。

5.2 构建与部署

  • 在本地执行 astro build,检查无报错、无错误链接。
  • dist/ 部署到测试域名或子路径,用浏览器与简单爬虫过一遍关键路径。

5.3 切换策略

  • 直接切换:将 Astro 构建结果部署到原域名根路径,旧 Wagtail 下线或仅保留后台只读。
  • 并行一段时间:Astro 站用新子域或新路径,旧站保留,再择机切主域并做 301。

完成以上四阶段,迁移的主干就打通了。

阶段小结:先「拿到数据」再「转成 Markdown」再「定 URL 与脚本」最后「验证再切换」,每一步都可单独回滚或重跑,建议每阶段做完都在本地 pnpm buildpnpm preview 跑一遍,再进入下一阶段。

本系列文章(一)为什么迁移与选型 · (二)迁移的几个阶段(本文) · (三)添加新文章 · (四)上线 · (五)数据同步与脚本化 · (六)主题与功能打磨