news 2026/9/13 18:35:18

Wagtail v3 API 实战:Sites 站点的增删改查接口与权限模型解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Wagtail v3 API 实战:Sites 站点的增删改查接口与权限模型解析

Wagtail v3 API 实战:Sites 站点的增删改查接口与权限模型解析

【免费下载链接】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/v3/sites/下提供了站点(Site)的完整 CRUD 能力:列表、详情、创建、更新、删除。本文以官方文档 docs/advanced_topics/api/v3/sites.md 为骨架,结合仓库内路由、Schema、模型与表单源码,逐层解析 Sites 端点的请求方式、字段语义、权限过滤逻辑以及其与后台管理界面共享的校验规则,帮助你直接用 HTTP 请求完成站点的全生命周期管理。

前置条件:启用 v3 API 并完成认证

Sites 端点是 v3 API 的一部分,使用前需要先完成两件事:启用 API 与获取访问令牌。

启用并挂载 v3 API

在 Django 项目设置中将wagtail.api.v3加入INSTALLED_APPS(参考 v3 API 快速开始):

# settings.py INSTALLED_APPS = [ ... 'wagtail.api.v3', ... ]

然后在urls.py中挂载 API 路由。由于 v3 目前仍处于预览阶段,官方建议挂载在/api/v3-preview/下以表明其可能随后续版本变化:

# urls.py from wagtail.api.v3.urls import api urlpatterns = [ path("api/v3-preview/", api.urls), # 也可以直接挂载在 /api/v3/ 下: # path("api/v3/", api.urls), ]

挂载后,浏览器可访问<API root>/docs/查看交互式文档,<API root>/openapi.json获取机器可读的 OpenAPI 3.1 Schema(两者默认公开,可通过WAGTAILAPI_DOCS_ENABLED设置关闭)。

获取 Bearer Token

Sites 端点仅接受认证请求,不提供匿名访问,因此每个请求都必须携带 Bearer Token。令牌的创建与权限模型详见 v3 API 认证文档,这里给出两种常用方式:

  • 后台界面:设置 → API tokenswagtail.api.v3INSTALLED_APPS中时可见),令牌明文只在创建时展示一次;
  • 命令行:使用管理命令创建,便于脚本化:
TOKEN=$(./manage.py api_tokens create --user=deploy --name="ci")

将令牌放入请求头:

curl -H "Authorization: Bearer $TOKEN" https://example.com/api/v3/whoami/

Sites 端点总览:五个 CRUD 操作

根据 sites.md 的说明,站点在/api/v3/sites/下以 CRUD 方式暴露:

方法路径说明成功状态码
GET/api/v3/sites/列出站点200
GET/api/v3/sites/{site_id}/返回单个站点200
POST/api/v3/sites/创建站点201
PUT/api/v3/sites/{site_id}/更新站点200
DELETE/api/v3/sites/{site_id}/删除站点204

这一组操作在源码中对应 wagtail/api/v3/routers/sites.py 里Router(tags=["sites"], auth=BearerTokenAuth())上注册的五个端点,每个端点都带有明确的 OpenAPI 元数据(summaryoperation_id),便于自动生成客户端。

一个站点由idhostnameportsite_nameroot_page_idis_default_site描述,列表与详情端点都会按权限策略过滤,调用者只能看到自己有权限的站点。

数据模型与字段语义

Sites 端点的响应与请求数据结构定义在 wagtail/api/v3/schemas/sites.py,底层对应wagtail.models.Site模型(见 wagtail/models/sites.py)。

响应 Schema:SiteSchema

class SiteSchema(Schema): id: int hostname: str port: int site_name: str root_page_id: int is_default_site: bool

请求 Schema:SiteInputSchema

class SiteInputSchema(Schema): hostname: str port: int = 80 site_name: str = "" root_page: int = Field(..., alias="root_page_id") is_default_site: bool = False

几个值得注意的字段细节:

  • port默认80:与Site模型port = models.IntegerField(default=80)一致。模型层面的帮助文本说明,只有需要在 URL 中体现特定端口时才需修改(例如本地开发端口 8000),它不影响请求处理,因此端口转发仍然有效;
  • site_name默认空字符串:模型上为max_length=255、可留空的可读名称;
  • root_page通过别名root_page_id接收:输入 Schema 刻意接受root_page_id以保持与输出字段一致,但在内部映射为root_page,从而能被SiteForm(一个 DjangoModelForm)直接接受;
  • is_default_site默认False:模型上默认为False,含义是"若为真,该站点将处理所有没有自己站点记录的其他主机名的请求"。

模型层面的核心约束

Site模型定义了两个关键约束(wagtail/models/sites.py):

  • unique_together = ("hostname", "port"):同一主机名加端口的组合全局唯一,这也是创建/更新时唯一性校验的底层依据;
  • 默认站点唯一性:clean_fields()中检查"是否已存在is_default_site=True的站点",若已存在其他默认站点,再设置新默认站点会抛出校验错误,提示必须先取消原默认站点。

hostname 规范化

Site.clean()会执行self.hostname = self.hostname.lower(),即主机名一律转为小写。由于 API 的创建与更新都走SiteForm,这个规范化规则同样作用于 API 写入——通过 API 传入WWW.Example.COM会与后台管理一样被规范化为www.example.com

权限模型:仅认证 + 权限策略过滤

Sites 端点与公开的页面、图片等只读端点不同,完全没有匿名访问。路由级别统一挂载了BearerTokenAuth(wagtail/api/v3/routers/sites.py 第 15 行),未认证请求直接失败。

在认证之外,每个端点还通过@require_any_permission(Site, ...)装饰器做二次权限校验,其权限集合来自 Wagtail 的policy_registry(权限策略注册表):

  • list_sitesget_site:要求调用者对Site拥有addchangedeleteview任一权限,并进一步通过instances_user_has_any_permission_for(request.user, ...)实例级别过滤——即列表与详情返回的站点,必须是当前用户对其持有任一上述权限的记录;
  • create_site:要求add权限;
  • update_site:要求change权限;
  • delete_site:要求delete权限。

这意味着令牌的访问范围与其绑定的用户账号权限完全一致(认证文档中明确"令牌允许的访问级别等同于其绑定的用户账号")。若需要对 API 做最小化授权,官方建议为 API 访问创建专用服务账号,赋予最小权限集,需要时直接吊销而不影响真实用户。结合源码结构可以推断:把站点排除在某用户权限之外,该用户的令牌在列表与详情响应中就看不到该站点,从而同时实现了可见性与可写性的双重控制。

创建站点:从 curl 到 action 的完整链路

官方文档给出了一个可直接复制的创建示例(路径按仓库根目录相对路径理解,实际部署时替换为你的 API 根):

curl -X POST "https://example.com/api/v3/sites/" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"hostname": "www.example.com", "port": 443, "site_name": "Example", "root_page_id": 4, "is_default_site": true}'

创建成功后返回201,响应体为完整的SiteSchema

底层调用链

创建端点的实现(wagtail/api/v3/routers/sites.py 第 52-66 行)展示了 API 与后台管理共享核心逻辑的设计:

@router.post( "/", response={201: SiteSchema}, url_name="create_site", summary="Create site", operation_id="sites_create", ) @require_any_permission(Site, ("add",)) def create_site(request: HttpRequest, data: SiteInputSchema): form = SiteForm(data.dict()) action_class = action_registry.get_action_class(Site, "create") action_class(form.instance, user=request.user, form=form).execute( skip_permission_checks=True ) return Status(201, form.instance)

关键点:

  1. SiteForm(data.dict()):请求 JSON 被转换为SiteForm(wagtail/sites/forms.py),其Meta.fields("hostname", "port", "site_name", "root_page", "is_default_site")。由于 API 传入的数据与后台表单同源,后台管理界面的所有规则都会生效:hostname 规范化(小写)、(hostname, port)唯一性约束、默认站点唯一性约束、root page 校验(root_page必须是指向有效Page的外键)以及后续的缓存失效逻辑;
  2. action_registry.get_action_class(Site, "create"):创建操作经由 Wagtail 的 action 注册表(wagtail/actions/registry.py)分派到Create动作类,与后台界面的保存走同一条业务路径,因此站点相关的 cache invalidation(清缓存/前端缓存失效信号)等副作用不会因为走 API 而缺失;
  3. skip_permission_checks=True:权限已在路由装饰器层校验过,action 内部不再重复检查;
  4. 状态码语义:创建返回201,删除返回204,与文档描述一致。

列出与查看站点:分页与权限过滤

# 列出站点 curl -H "Authorization: Bearer $TOKEN" "https://example.com/api/v3/sites/?limit=20&offset=0" # 查看单个站点 curl -H "Authorization: Bearer $TOKEN" "https://example.com/api/v3/sites/4/"

列表端点使用 limit/offset 分页(WagtailLimitOffsetPagination,与 v3 API 全局分页一致),响应形如:

{ "count": 42, "items": [] }

其中count是不受分页影响的全部结果数;?limit?offset用于翻页,limit上限由WAGTAILAPI_LIMIT_MAX设置控制(详见 API 设置参考 及 v2 配置文档)。

值得注意的是列表查询的权限过滤实现:list_sites返回policy_registry.get_by_type(Site).instances_user_has_any_permission_for(request.user, ("add", "change", "delete", "view")),即数据库查询层就完成了按用户权限的站点筛选;详情端点get_site则把同一查询集交给get_object_or_404对无权限的site_id返回404而非403,避免泄露站点是否存在。

更新与删除站点

# 更新站点(PUT 整体替换) curl -X PUT "https://example.com/api/v3/sites/4/" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"hostname": "www.example.com", "port": 443, "site_name": "Example v2", "root_page_id": 4, "is_default_site": true}' # 删除站点 curl -X DELETE "https://example.com/api/v3/sites/4/" \ -H "Authorization: Bearer $TOKEN"

更新端点使用SiteForm(data.dict(), instance=site)绑定既有实例,再经 action 注册表分派到edit动作执行;删除端点分派到delete动作并返回204 No Content。与创建一样,更新和删除都要求相应权限(change/delete),且同样经由 Wagtail action 体系触发后续的缓存失效与日志记录等副作用。

错误处理约定

v3 API 的统一错误处理同样适用于 Sites 端点(详见 v3 API 概览):处理过的 API 错误采用 RFC 7807 的application/problem+json格式,包括校验失败(HTTP 422)、权限失败(未认证401、已认证但无权403)、404等。例如提交非法数据(如重复的 hostname/port 组合)会得到形如:

{ "type": "about:blank", "title": "Unprocessable Entity", "status": 422, "detail": "Validation failed", "errors": [] }

errors数组中会包含SiteForm校验失败的字段级细节。

测试验证与 OpenAPI 参考

仓库在 wagtail/api/v3/tests/test_sites.py 中为 Sites 端点提供了完整的测试覆盖(列表、详情、创建、更新、删除及权限行为),并在wagtail/api/v3/tests/snapshots/openapi.json的快照中固化每个端点的 OpenAPI 描述——这也是文档中"完整生成的 OpenAPI 参考来自 Wagtail 自身的 OpenAPI 快照"一说的来源。

需要完整的端点到字段级别的 OpenAPI 定义时,可直接访问自己实例的<API root>/openapi.json,或阅读 v3 API OpenAPI 参考文档 中的生成参考。想了解 v3 整体设计(分页、错误处理、与其他资源的对应关系)可继续阅读 v3 API 索引 与 Schema 文档。

小结

Wagtail v3 API 的 Sites 端点是一个"仅认证 + CRUD + 复用后台表单与 action 体系"的典型实现:五个端点覆盖站点生命周期,字段与Site模型一一对应,写入路径与后台管理共享SiteForm的全部校验规则(hostname 规范化、唯一性、默认站点约束、root page 校验、缓存失效),而权限策略注册表则保证了列表、详情、写操作三级的细粒度控制。对于需要以编程方式管理多站点 Wagtail 项目的团队,这组端点提供了一个与后台界面行为一致、可脚本化的站点管理入口。

【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 18:34:08

3 步装好并激活 Office:LKY Office Tools 一键部署实操记录

3 步装好并激活 Office&#xff1a;LKY Office Tools 一键部署实操记录 【免费下载链接】LKY_OfficeTools 一键自动化 下载、安装、激活 Office 的利器。 项目地址: https://gitcode.com/GitHub_Trending/lk/LKY_OfficeTools 重装系统后 Office 装不上&#xff0c;是很多…

作者头像 李华
网站建设 2026/9/13 18:31:20

Beads 项目 npm 包发布指南:@beads/bd 的发布全流程与源码级解析

Beads 项目 npm 包发布指南&#xff1a;beads/bd 的发布全流程与源码级解析 【免费下载链接】beads Beads - A memory upgrade for your coding agent 项目地址: https://gitcode.com/GitHub_Trending/beads1/beads 本文以仓库内 npm-package/PUBLISHING.md 为主干&…

作者头像 李华
网站建设 2026/9/13 18:30:23

PDF补丁丁教程:免费搞定 PDF 合并、书签生成与文档修复的 5 个任务

PDF补丁丁教程&#xff1a;免费搞定 PDF 合并、书签生成与文档修复的 5 个任务 【免费下载链接】PDFPatcher PDF补丁丁——PDF工具箱&#xff0c;可以编辑书签、剪裁旋转页面、解除限制、提取或合并文档&#xff0c;探查文档结构&#xff0c;提取图片、转成图片等等 项目地址…

作者头像 李华
网站建设 2026/9/13 18:27:16

相位驱动的机器学习角色动画:简化PFNN实现指南

简介&#xff1a;这是一份面向动画技术研究与机器学习初学者的实践资源&#xff0c;聚焦用简化版部分融合神经网络&#xff08;PFNN&#xff09;生成运动学动画&#xff0c;覆盖数据预处理、模型构建、训练与结果可视化完整流程。压缩包共37个文件&#xff0c;以15个Python源码…

作者头像 李华