Wagtail 2.8 版本发布全解析:Django 3.0 支持、独占式页面锁定与 API 端点迁移指南
【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail
导读
本文基于 Wagtail 官方 2.8 版本发布说明(docs/releases/2.8.rst,发布于 2020 年 2 月 3 日),系统梳理该版本的核心变更:Django 3.0 兼容支持、页面锁定机制从"全员只读"升级为"锁定者独占编辑"、新增锁定页面报告菜单,以及 API 端点类重命名等破坏性升级项。读者将掌握 2.8 版本的新特性细节、从旧版本升级时需要注意的破坏性变更清单,以及每项变更对应的源码实现位置,便于在升级后快速定位与验证。
一、版本总览:2.8 带来了什么
Wagtail 2.8 是面向 Django 3.0 时代的一次重要版本迭代,核心看点集中在以下三方面:
- Django 3.0 官方兼容:该版本与 Django 3.0 完全兼容,兼容性修复由 Matt Westcott 和 Mads Jensen 贡献。
- 页面锁定(Page Locking)机制重构:过去锁定页面后所有用户(包括锁定者本人)都只能只读访问;2.8 改为锁定者获得独占编辑权,其他用户无法编辑。同时新增 Reports 菜单,管理员/版主可查看当前所有被锁定的页面并按需解锁。
- 一批破坏性升级项:包括移除 Django 2.0 支持、API 端点类重命名迁移、
get_document_model导入路径调整、Page/Site模型移出 Django admin、嵌入媒体响应式包装类默认关闭等,升级前务必逐项核对。
该版本由 Karl Hobley 和 Jacob Topp-Mugglestone 主导页面锁定功能开发,The Motley Fool 赞助了该特性。
二、Django 3.0 支持与 Python 兼容性清理
2.1 与 Django 3.0 的兼容
2.8 是 Wagtail 全面拥抱 Django 3.0 的版本。Django 3.0 于 2019 年 12 月发布,引入了对 Python 3.8 的支持、ASGI 异步支持等特性。Wagtail 2.8 通过兼容性修复确保在 Django 3.0 下稳定运行。
2.2 Python 2.x 兼容代码清理
该版本同时移除了残留的 Python 2.x 兼容代码(由 Sergey Fedoseev 完成),并合并了 flake8 配置。这意味着 Wagtail 2.8 及后续版本在代码层面已明确面向 Python 3 演进,项目自身的运行环境也应确保使用 Python 3.6 及以上版本。
三、改进的页面锁定(Page Locking):从"全员只读"到"锁定者独占编辑"
3.1 旧行为与新行为对比
页面锁定是 Wagtail 内容审核中的关键机制,用于防止多人在同一页面上同时编辑造成冲突。2.8 之前,一旦页面被锁定,包括锁定者在内的所有用户都无法编辑,页面整体变为只读。这种"一刀切"方式让锁定者自己也失去了编辑能力,往往需要先解锁再编辑,操作繁琐且容易产生中间状态。
2.8 的核心变更在于:
- 锁定页面后,锁定者本人仍然可以继续编辑,拥有独占编辑权;
- 其他所有用户无法编辑,只能只读访问;
- 锁定信息(锁定人、锁定时间)被完整记录,管理员可查看并解除。
3.2 从源码看锁定的实现
当前仓库中,页面锁定相关的数据模型与权限逻辑集中体现在 wagtail/models/pages.py:
- 页面模型持有
locked、locked_by、locked_at字段(见 wagtail/models/pages.py 附近的字段序列化清单),其中locked_by记录执行锁定的用户,locked_at记录锁定时间; PagePermissionsTester提供权限判定方法:user_has_lock()(判断当前用户是否就是锁定者,见 wagtail/models/pages.py)、can_lock()(是否允许执行锁定)与can_unlock()(是否允许解除锁定,见 wagtail/models/pages.py)。
管理员侧的锁定/解锁操作视图位于 wagtail/admin/views/pages/lock.py:LockView.perform_operation会先检查permissions_for_user(user).can_lock(),无权限则抛出PermissionDenied;UnlockView对应检查can_unlock(),解锁成功后返回提示消息"Page 'xxx' is now unlocked."。
3.3 新增 Reports 菜单:锁定页面报告
为了配合新锁定机制,2.8 在管理后台的Reports(报告)菜单中新增了"Locked pages"(锁定页面)入口,允许具有 unlock 权限的管理员/版主:
- 查看当前所有处于锁定状态的页面;
- 按"锁定人"(Locked by)、"锁定时间"(Locked at)和"是否已发布"(live)进行筛选;
- 直接在列表中执行解锁操作。
对应实现为 wagtail/admin/views/reports/locked_pages.py 中的LockedPagesView:
- 使用
WagtailFilterSet定义筛选器LockedPagesReportFilterSet,其中locked_at使用DateRangePickerWidget日期范围选择器,locked_by使用ModelChoiceFilter,空选项文案为"Anyone"; get_queryset()将"当前用户有 change 权限的页面"与"当前用户自己锁定的页面"取并集,再过滤locked=True,从而保证报告展示内容与用户权限范围一致;- 支持导出(
list_export扩展了locked_at、locked_by字段),文件名格式为locked-pages-report-YYYY-MM-DD; - 权限要求为
unlock(permission_required = "unlock"),即只有具备解锁权限的用户才能查看该报告。
报告模板位于 wagtail/admin/templates/wagtailadmin/reports/locked_pages_results.html,解锁操作列表项模板为 wagtail/admin/templates/wagtailadmin/reports/listing/_list_unlock.html。
3.4 配置项:恢复旧行为
若希望恢复 2.8 之前"锁定后全员只读"的行为,可在项目设置中显式开启:
WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK = True需要特别注意:该设置只对 2.8 之后新锁定的页面生效。在 2.8 发布之前就已处于锁定状态的页面,会继续保持旧的"全员只读"行为,不受新机制影响。
四、其他新增特性详解
2.8 除两大主线特性外,还有一批值得关注的增强,以下结合当前仓库源码逐一说明。
4.1 前端缓存:Cloudflare API Token 支持与分批清理
Wagtail 的前端缓存清理模块新增了对Cloudflare API Token的支持(此前仅支持 API Key 方式),用于在页面发布/更新时自动失效 CDN 缓存。相关实现位于 wagtail/contrib/frontend_cache/backends/cloudflare.py:
CloudflareBackend通过requests.post调用 Cloudflare purge cache API;- 由于 Cloudflare 单次 purge 请求存在数量上限,2.8 起每 30 个 URL 分批发送。源码中定义了
CHUNK_SIZE = 30,purge_batch()使用range(0, len(urls), self.CHUNK_SIZE)将批量 URL 切片后逐个分块调用_purge_urls; - 测试用例 wagtail/contrib/frontend_cache/tests.py 中的
test_cloudflare_purge_batch_chunked专门验证了 64 个 URL 会被正确分批清理,防止单次请求超出 API 限制。
4.2 嵌入媒体:新增WAGTAILEMBEDS_RESPONSIVE_HTML设置
此前 Wagtail 渲染嵌入媒体(如 YouTube 视频)时,会自动在外层包装一个带responsive-object类名和padding-bottom内联样式的 div,用于辅助响应式布局。2.8 起该包装默认不再添加,改为通过设置显式控制:
WAGTAILEMBEDS_RESPONSIVE_HTML = True在源码中,该设置的判断位于 wagtail/embeds/models.py:Embed.is_responsive属性首先检查settings.WAGTAILEMBEDS_RESPONSIVE_HTML是否为真,再判断是否存在宽高比(ratio)。模板 wagtail/embeds/templates/wagtailembeds/embed_frontend.html 根据embed.is_responsive决定是否输出class="responsive-object"与padding-bottom样式:
<div{% if embed.is_responsive %} style="padding-bottom: {{ embed.ratio_css }};" class="responsive-object"{% endif %}> {{ embed.html|safe }} </div>对应测试见 wagtail/embeds/tests/test_rich_text.py:开启设置时输出包含class="responsive-object",关闭时则不包含。
4.3 Admin API:pages 端点新增ancestors字段
Admin API 的 pages 端点新增了ancestors字段,便于前端获取页面的祖先层级链,对面包屑导航、站点树渲染等场景很有帮助。
4.4 文档管理:缓存控制头与模型工具函数
- 文档下载响应增加缓存控制头(
cache control headers),提升文档静态资源的分发效率; - 新增
get_document_model_string函数,并调整了get_document_model的位置,使其在模型尚未加载时也能安全导入。当前实现位于 wagtail/documents/init.py:get_document_model_string()返回形如"wagtaildocs.Document"的字符串,get_document_model()依赖它完成动态模型解析,并提供了get_document_model_string()的便捷入口。
4.5 其他改进
- 文本字段 diff 行为优化:比较页面修订版本时,文本字段的差异展示更准确;
- 禁用输入控件对比度提升:改善可访问性;
- 文档列表列名调整:'uploaded' 更名为 'created';
- 图片索引支持按标签筛选:图片管理页可按 tag 过滤;
- 嵌套 InlinePanel 的部分实验性支持:由 Matt Westcott、Sam Costigan、Andy Chosak、Scott Cranfill 共同贡献,注意是"部分 + 实验性"支持,生产环境使用需谨慎评估;
- 密码重置表单使用
sensitive_post_parameters:防止敏感参数被错误记录到日志; - StreamFieldPanel 与 ModelAdmin 自定义文档补全:
{{ block.super }}示例被补充到 ModelAdmin 自定义文档中,所有包含extra_js/extra_css的模板(wagtailsettings、modeladmin)统一使用block.super,避免覆盖父模板资源; - 移除 Django admin 对
Page与Site模型的管理(见下文升级说明)。
五、Bug 修复清单
2.8 修复了一批影响实际使用的问题,按主题归类如下:
| 主题 | 修复内容 |
|---|---|
| 文档模块 | file_size与file_hash在文档文件变更后正确更新;get_document_model移至模型未加载时也能导入的位置 |
| 嵌入/富文本 | Jinja2 表单模板中 StructBlock 的 HTML 转义问题;TableBlock 空白时不再导致update_index失败及前端渲染错误 |
| 比较/审核 | 比较引用了自定义主键模型的页面时不再报错;模态框 chooser 搜索会取消上一次请求,确保结果始终对应当前最新搜索关键词 |
| 界面与布局 | FieldRowPanel带标题时布局问题修复;搜索页 AJAX 调用后下拉框初始化问题修复 |
| 项目模板 | URL 顺序修正,确保 static / media URL 不被拦截 |
| 国际化 | 表单提交模型的verbose_name_plural补全;解绑 l18n 库(此前因安装错误被捆绑,现已解决) |
| 表单/权限 | 所有含 wagtailsettings 与 modeladmin 的模板统一使用block.super输出extra_js/extra_css |
六、升级注意事项(破坏性变更清单)
升级到 2.8 前,请逐项核对以下变更,它们可能影响现有代码与运行行为。
6.1 移除 Django 2.0 支持
Django 2.0 不再受支持。升级 Wagtail 之前,请先将项目升级到 Django 2.1 或以上版本(推荐直接使用 Django 3.0)。
6.2 编辑锁定行为变更
如第三节所述,锁定行为从"全员只读"变为"锁定者独占编辑"。此变更仅影响2.8 之后新锁定的页面;升级前已锁定的页面维持旧行为。如需恢复旧行为,设置:
WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK = True6.3 嵌入响应式 HTML 默认关闭
嵌入媒体不再默认包裹responsive-object。若你的前端样式依赖该包装类,请在项目设置中加入:
WAGTAILEMBEDS_RESPONSIVE_HTML = True6.4 API 端点类迁移:*APIEndpoint→*APIViewSet
为与 Django REST Framework 命名惯例保持一致,PagesAPIEndpoint、ImagesAPIEndpoint、DocumentsAPIEndpoint分别更名为PagesAPIViewSet、ImagesAPIViewSet、DocumentsAPIViewSet,并迁移到各自包内的views模块。当前仓库中的新位置为:
- wagtail/api/v2/views.py:
PagesAPIViewSet - wagtail/images/api/v2/views.py:
ImagesAPIViewSet - wagtail/documents/api/v2/views.py:
DocumentsAPIViewSet
升级时需更新 API 注册代码。旧代码:
from wagtail.api.v2.endpoints import PagesAPIEndpoint from wagtail.api.v2.router import WagtailAPIRouter from wagtail.images.api.v2.endpoints import ImagesAPIEndpoint from wagtail.documents.api.v2.endpoints import DocumentsAPIEndpoint api_router = WagtailAPIRouter('wagtailapi') api_router.register_endpoint('pages', PagesAPIEndpoint) api_router.register_endpoint('images', ImagesAPIEndpoint) api_router.register_endpoint('documents', DocumentsAPIEndpoint)新代码:
from wagtail.api.v2.views import PagesAPIViewSet from wagtail.api.v2.router import WagtailAPIRouter from wagtail.images.api.v2.views import ImagesAPIViewSet from wagtail.documents.api.v2.views import DocumentsAPIViewSet api_router = WagtailAPIRouter('wagtailapi') api_router.register_endpoint('pages', PagesAPIViewSet) api_router.register_endpoint('images', ImagesAPIViewSet) api_router.register_endpoint('documents', DocumentsAPIViewSet)6.5get_document_model导入路径变更
get_document_model函数应改从wagtail.documents导入,而不是wagtail.documents.models:
from wagtail.documents import get_document_model自定义文档模型的完整指引可参考文档 docs/reference/pages/models.md 中关于自定义模型的部分。这一调整的动机正是 Bug 修复中提到的"使该函数在模型尚未加载时也能被安全导入"(参见 wagtail/documents/init.py)。
6.6Page与Site模型移出 Django admin
Page与Site模型不再通过 Django admin 后台管理。如果你的项目确实需要在 Django admin 中维护这两个模型,可在自己的应用中重新注册,示例:
# my_app/admin.py from django.contrib import admin from wagtail.core.models import Page, Site admin.site.register(Site) admin.site.register(Page)注意:注册Page模型会启用对整棵页面树的 Django admin 管理入口,请结合你的权限体系谨慎评估是否必要。
七、升级建议小结
完成 Wagtail 2.8 升级时,建议按以下顺序操作:
- 将 Django 升级到 2.1+(推荐 3.0),Python 保持 3.x;
- 全局搜索项目中的
APIEndpoint引用并替换为对应的APIViewSet,同时修正 import 路径; - 将
get_document_model的导入改为from wagtail.documents import get_document_model; - 检查是否依赖嵌入媒体的
responsive-object包装,按需开启WAGTAILEMBEDS_RESPONSIVE_HTML; - 确认页面锁定新行为是否符合团队协作流程,若需旧行为则设置
WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK = True; - 如项目使用 Cloudflare 前端缓存,可迁移到 API Token 认证方式,并确认 30 条/批的分块清理逻辑;
- 检查 Django admin 中是否依赖
Page/Site的管理入口,按需重新注册; - 运行项目测试套件,重点回归页面锁定、嵌入渲染、文档上传/下载与 API 端点。
升级后的验证可从 wagtail/admin/tests/pages/test_page_locking.py 与 wagtail/admin/tests/test_reports_views.py 中了解锁定与报告功能的官方测试行为,作为自测的参考基线。
【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考