)
Wagtail API v3 实战指南基于 Django Ninja 的读写内容 APIWagtail 8.0 预览版【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail本文基于 Wagtail 8.0 引入的 v3 API 预览文档讲解这套基于 Django Ninja 与类型提示构建的新 API如何在 Django 项目中挂载它、如何通过 OpenAPI 3.1 Schema 做类型发现、如何使用 limit/offset 分页以及如何理解其 RFC 7807 风格的结构化错误响应。读完本文你可以将 v3 API 作为 Wagtail 内容后端的读写接口接入前端、Headless 站点或自动化脚本并对照仓库源码理解每个行为的底层实现。什么是 Wagtail API v3Wagtail 8.0 引入了新版 v3 API 的预览preview。与传统 v2 REST API 不同v3 的核心技术特征是构建于 Django Ninja 之上采用 Ninja 的 Router / Schema / 分页体系而不是 v2 中手写的 view 与序列化器组合全面使用类型提示type hints请求与响应结构以 Pydantic Schema 声明从而支持类型检查与自动文档生成导出 OpenAPI 3.1 Schema客户端可以从openapi.json获得完整的机器可读接口定义声明式的按类型 Schema每种内容类型如各类 Page 模型都有独立的 read/create/patch Schema而不是所有模型共用一个宽泛的序列化器同时支持读取与写入的 CMS 操作设计目标是覆盖 RFC 115 中描述的读写能力大致对齐 Wagtail 后台管理界面所能完成的常见操作。需要注意v3 目前处于preview状态官方建议挂载在/api/v3-preview/路径下以表明其可能随后续版本调整。快速开始安装与挂载1. 注册应用首先把wagtail.api.v3加入 Django 项目的INSTALLED_APPS# settings.py INSTALLED_APPS [ ... wagtail.api.v3, ... ]对应的应用配置类定义在 apps.py 中应用标签为wagtailapi_v3其ready()钩子会额外调用APIRichText.check_setting()校验富文本格式相关设置详见下文“与 v2 共享的配置”。2. 挂载 URL在项目的 URL 配置中注册 API。预览阶段推荐挂载到/api/v3-preview/# urls.py from wagtail.api.v3.urls import api urlpatterns [ path(api/v3-preview/, api.urls), # You can also mount it at /api/v3/ if you prefer: # path(api/v3/, api.urls), ]从 urls.py 的模块文档字符串可以看到两点关键约束挂载方式与 v2 保持一致api.urls是一个可挂载的 URL 对象保证 v2 用户的迁移成本低所有 Router 必须在访问api.urls之前注册到api实例上否则 Django Ninja 会抛出ConfigError。Wagtail 内部已经在 api.py 中完成了 Router 注册# wagtail/api/v3/api.py节选 api.add_router(/pages/, pages_router) api.add_router(/schema/, schema_router) api.add_router(/sites/, sites_router) api.add_router(/, whoami_router)也就是说当前随包提供的路由包括页面/pages/、Schema 发现/schema/、站点/sites/以及根路径下的whoami端点。3. 浏览生成的文档挂载成功后两个开箱即用的入口会自动暴露人类可读的文档仪表盘API root/docs/例如/api/v3-preview/docs/机器可读的 OpenAPI SchemaAPI root/openapi.json。这两个路由的定义可以直接在NinjaAPI实例参数中确认api.pyapi NinjaAPI( titleWagtail API, version3.0.0, descriptionWagtail v3 read and write API, urls_namespacewagtailapi_v3, docs_decorator_gate_docs, openapi_url/openapi.json, docs_url/docs/, )OpenAPI Schema 与文档仪表盘默认是公开可访问的包含匿名端点与认证端点的描述。如果希望隐藏这两条路由把设置WAGTAILAPI_DOCS_ENABLED设为False即可。其实现是一个简单的装饰器门控api.pydef _gate_docs(view): Uses WAGTAILAPI_DOCS_ENABLED to 404 the OpenAPI schema / interactive docs. wraps(view) def wrapper(request, *args, **kwargs): if not getattr(settings, WAGTAILAPI_DOCS_ENABLED, True): raise Http404 return view(request, *args, **kwargs) return wrapper即关闭后这两条路由会直接返回 404而非 403对探测者而言表现为“不存在”。端点组成与按应用动态启用的机制v3 API 暴露哪些端点取决于项目中安装了哪些 Wagtail 应用Pages 端点始终可用Images、Documents、Snippets、Locales、Redirects 端点只有在对应应用位于INSTALLED_APPS且相应模型完成注册时才会出现。从源码结构看这一动态发现机制由 registry.py 中的ContentTypeRegistry支撑模块导入时会立即调用registry.register_defaults()注册所有页面模型并为每个模型生成三个方向的 Pydantic Schemaread/create/patch# wagtail/api/v3/registry.py节选 def register_defaults(self) - None: Register the content types shipped with Wagtail (currently pages). from wagtail.models import get_page_models for model in get_page_models(): read_schema read_generator.generate_schema(model, base_classPageSchema) ... self.register(ContentTypeRegistration( namemodel._meta.label, labelstr(model._meta.verbose_name), read_schemaread_schema, create_schemacreate_schema, patch_schemapatch_schema, ))/schema/路由消费这个注册表让客户端先“发现”有哪些内容类型再查询每种类型的 read/create/patch JSON Schema某个方向没有 Schema 时会返回占位符{description: Not available.}。注册时机上的一个细节值得注意源码注释说明register_defaults()之所以放在模块导入时而不是AppConfig.ready()中执行是因为 Router 模块在自身导入阶段就要读取注册内容来构建请求/响应 Schema若依赖ready()会引入INSTALLED_APPS顺序的隐式依赖见 registry.py。v3 覆盖的功能范围文档明确列出了 v3 API 支持的 CMS 操作大致对齐 Wagtail 后台管理界面页面Pages包括草稿drafts、修订revisions与页面操作page actions站点Sites、语言locales与重定向redirects图片images与文档documents启用了 API 的 Snippets富文本支持 HTML 与 Markdown 两种格式StreamField 内容Schema 发现与 OpenAPI 参考。文档同时坦诚列出了当前尚未覆盖、期待社区反馈的方向工作流 / 审核操作提交、批准、驳回等Site settings 支持更精确的 StreamField block Schema复用该 API 的官方客户端库或 UIv2 API 的弃用与最终移除计划官方 API 教程。v3 的每个子主题在仓库文档中都有独立章节可按需深入认证Pages 端点Images 端点Documents 端点Snippets 端点Redirects 端点StreamField 内容富文本HTML/MarkdownSites 端点Locales 端点Schema 发现完整参考从 v2 迁移指南分页limit/offset 与 count 语义所有列表端点使用limit/offset 分页响应中的count是不受分页影响的总结果数{ count: 42, items: [] }通过?limit与?offset查询参数翻页WAGTAILAPI_LIMIT_MAX限制limit的上限。实现细节见 pagination.pyWagtailLimitOffsetPagination继承 Ninja 的LimitOffsetPagination并做了两处与 v2 对齐的关键调整默认limit为 20Wagtail 的 API 默认值而不是 Ninja 原生的 100class Input(LimitOffsetPagination.Input): limit: int Field(default20, ge1) offset: int Field(default0, ge0)超限行为不同当limit超过WAGTAILAPI_LIMIT_MAX时v3 直接抛出400错误limit cannot be higher than {max}与 v2 行为一致而 Ninja 基础分页器会静默地把 limit 截断到上限def paginate_queryset(self, queryset, pagination, request, **params): max_limit _get_max_limit() if max_limit ! inf and pagination.limit int(max_limit): raise HttpError(400, flimit cannot be higher than {int(max_limit)}) return super().paginate_queryset(queryset, pagination, request, **params)其中WAGTAILAPI_LIMIT_MAX的默认值为 20设为None时上限为无穷见_get_max_limit。错误处理RFC 7807 的 application/problemjsonv3 API 的所有受控错误统一使用 RFC 7807 定义的application/problemjson媒体类型返回。覆盖范围包括场景状态码说明Schema / 内容 / 模型层校验失败422含逐字段errors列表未认证访问受保护端点401Authentication required已认证但权限不足403附带权限错误信息资源不存在404Not found富文本格式错误400由RichTextFormatError触发一个校验失败的响应示例{ type: about:blank, title: Unprocessable Entity, status: 422, detail: Validation failed, errors: [] }对应的实现集中在 errors.py几个值得了解的点错误体结构由 Pydantic Schema 声明ProblemDetail包含type、title、status、detail、errors五个字段默认type为about:blanktitle缺省时取 HTTP 状态短语如 422 对应Unprocessable Entity多种校验异常归一到 422Pydantic 校验错误、Ninja 校验错误、DjangoValidationError以及表单校验异常FormValidationError都会经validation_error_handler统一包装为 422 响应并各自转换出对应格式的errors列表401 与 403 的判定逻辑从源码注释看v3不信任基于会话的认证——只有当 bearer token 成功解析出用户时才返回 403否则一律 401errors.pyapi.exception_handler(PermissionDenied) def permission_denied_handler(request, exc): # v3 never trusts session auth: 401 unless a bearer token resolved. if not request.user.is_authenticated: return problem_response(status401, detailAuthentication required) return problem_response(status403, detailstr(exc) or Permission denied)未处理异常的边界行为未匹配到任何处理器的异常不会被转换成 problemjson 信封。在生产环境DEBUGFalse中它们会被重新抛出交由 Django 自身的错误处理机制因此响应格式可能不是application/problemjson仅在DEBUGTrue时才会以 500 的 problem 响应返回errors.py。这些行为的回归测试分别位于 test_errors.py、test_docs.py 与 test_openapi_snapshot.py后者用快照文件 openapi.json 锁定 OpenAPI 输出可用于观察 Schema 的演进。与 v2 共享的配置项v3 API 在适用之处读取与 v2 相同的WAGTAILAPI_*设置这意味着已有 v2 项目的配置可以平滑沿用WAGTAILAPI_BASE_URL用于生成响应中绝对 URL 的基础地址WAGTAILAPI_LIMIT_MAX分页limit的上限默认 20None表示不限制WAGTAILAPI_SEARCH_ENABLED是否启用搜索参数WAGTAILAPI_RICH_TEXT_FORMAT富文本输出格式HTML / Markdown。各设置的完整定义见 API 设置参考v2 的配置说明见 v2 配置文档。集成建议与小结由于 v3 处于 preview 阶段接入时请挂载在/api/v3-preview/并关注 迁移指南 中关于 v2 → v3 差异的说明优先利用openapi.json与/docs/做客户端代码生成而非手工拼请求需要对外隐藏文档时设置WAGTAILAPI_DOCS_ENABLED False客户端错误处理应以application/problemjson为契约先检查status与title再解析 422 响应中的errors列表做字段级提示记住分页语义count是总数limit默认 20超过WAGTAILAPI_LIMIT_MAX会得到 400 而不是被静默截断需要写操作时先通过 认证文档 配置 token 认证v3 对会话认证的信任策略与 v2 不同未解析出 bearer token 一律 401。整体来看v3 API 用 Django Ninja Pydantic 类型体系换取了自动化的 OpenAPI 3.1 文档、按内容类型声明的 read/create/patch Schema以及结构化的 RFC 7807 错误契约——这正是它对 v2 的核心增量也是其作为 Wagtail Headless 读写接口未来演进方向的基础。【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考