尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Wagtail v3 API 文档管理完整指南:Documents 端点的读写、权限与自定义模型

Wagtail v3 API 文档管理完整指南:Documents 端点的读写、权限与自定义模型 Wagtail v3 API 文档管理完整指南Documents 端点的读写、权限与自定义模型【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtailDocuments文档是 Wagtail 内容管理系统中最常用的资源类型之一。本文围绕 Wagtail 仓库中 docs/advanced_topics/api/v3/documents.md 这一核心文档展开系统讲解 v3 API 中文档的列表/读取、上传、元数据更新、删除四个操作深入剖析其集合权限与视图限制模型、multipart 上传与 JSON 更新两种请求形态并结合仓库源码说明自定义文档模型如何无缝接入 API。读完本文你将能够在自己的 Wagtail 项目中使用curl或任意 HTTP 客户端完整地通过/api/v3/documents/管理文档并理解其底层实现原理。概述扁平路由与读写权限分工v3 API 将文档统一挂载在/api/v3/documents/下路由是扁平的直接挂在集合之下而不是嵌套在collections内部。对应的路由实现位于 wagtail/documents/api/v3/router.py四个端点分别为方法路径操作权限要求GET/api/v3/documents/列出文档匿名 Bearer 均可GET/api/v3/documents/{id}/读取单个文档匿名 Bearer 均可POST/api/v3/documents/上传新文档需认证 文档add权限PATCH/api/v3/documents/{id}/更新文档元数据需认证 文档change权限DELETE/api/v3/documents/{id}/删除文档需认证 文档delete权限一个最核心的设计原则是读公开、写受限。文档读取默认对匿名请求公开而上传、元数据更新和删除则始终要求携带 Bearer Token 的认证请求且操作者必须拥有对应权限。权限检查通过require_any_permission装饰器实现见 wagtail/api/v3/permissions.py它会经由policy_registry查询用户对文档模型的权限与在管理后台执行相同操作时使用的是同一套权限体系。认证机制本身在 docs/advanced_topics/api/v3/authentication.md 中有完整说明Token 与用户账号绑定API 请求以该用户的身份和 Wagtail 权限执行。Token 可以通过后台Settings → API tokens创建也可用命令行创建TOKEN$(./manage.py api_tokens create --userdeploy --nameci)读取文档公开访问与集合视图限制响应结构GET /documents/返回文档列表GET /documents/{id}/返回单个文档。文档响应包含其id、title、collection、tags以及type、detail_url详情 URL和download_url绝对下载 URL。从 wagtail/documents/api/v3/schemas.py 可以看到响应 schema 的定义顶层字段idint、titlestr、collection外键 schema包含主键与meta.typemeta块type文档模型标签、detail_url、tags字符串列表、download_url。download_url只有在文档确实关联了文件时才返回否则为null。{ id: 7, title: Acceptable use policy, collection: {id: 3, meta: {type: wagtailcore.Collection}}, meta: { type: wagtaildocs.Document, detail_url: https://example.com/api/v3/documents/7/, tags: [], download_url: https://example.com/media/documents/policy.pdf } }集合视图限制View Restriction的判定逻辑两个读取端点虽然允许匿名访问但存在一个关键的可见性规则当文档自身所属集合上直接挂有未被当前请求满足的视图限制时该文档会被排除。带 Bearer Token 的请求可以通过用户身份、所属组身份满足登录/组限制密码限制则依据会话session状态判定——这与 v3 其他资源如页面的读取行为完全一致。这一逻辑在源码中有精确实现。读取端点的查询集构造位于 router.pydef get_documents_queryset(request): restricted_collection_ids get_restricted_collection_ids(request) return ( Document.objects.exclude(collection__inrestricted_collection_ids) .prefetch_related(tags) .order_by(id) )而get_restricted_collection_idswagtail/api/v3/permissions.py会遍历所有CollectionViewRestriction收集请求未能满足的限制所属集合 ID并沿集合树向下传播path__startswith匹配子集合最终得到一个受限集合 ID 集合查询时直接exclude掉。这里有一个容易混淆的细节文档以醒目的方式提醒祖先集合上的限制不会隐藏后代集合中的文档——只有挂在文档自身所属集合上的限制才会影响其可见性。这个行为有测试覆盖见 wagtail/documents/tests/test_api_v3/test_listing.py 中的test_direct_login_restriction_excludes_anonymous直接限制排除匿名用户、test_direct_login_restriction_accepts_bearer_userBearer 用户通过登录限制、test_direct_group_restriction_checks_bearer_user_groups组限制按用户组判定、test_direct_password_restriction_accepts_passed_session密码限制尊重会话以及test_ancestor_restriction_hides_descendant_document。值得注意的对比是 test_detail.py 中的test_ancestor_restriction_returns_404与test_direct_restriction_returns_404——单文档详情端点对受限文档返回404而非 403这样既隐藏了文档存在性又保证了匿名响应的一致性。列表的分页、过滤、排序与全文搜索文档列表支持?limit/?offset分页详见 docs/advanced_topics/api/v3/index.md响应中的count是不受分页影响的结果总数。分页器实现位于 wagtail/api/v3/pagination.py默认limit为 20且受WAGTAILAPI_LIMIT_MAX约束超出时返回 400 错误。过滤方面可以对文档自身字段id和title以及项目通过api_fields声明的额外字段做精确匹配查询参数过滤也可以排序和全文搜索。结合文档中的示例# Documents titled report, ordered by title curl https://example.com/api/v3/documents/?titlereportordertitle # Search documents for policy curl https://example.com/api/v3/documents/?searchpolicy实现上router.py 的list_documents用APIFieldFilterSchema构建基于request.GET的动态过滤 schema基础可过滤字段为BASE_DOCUMENT_READ_FIELDS [id, title]随后依次执行字段过滤、排序OrderingSchema与搜索SearchSchema。搜索功能由WAGTAILAPI_SEARCH_ENABLED开关控制文档模型在 wagtail/documents/models.py 中通过index.SearchField(title)、index.FilterField(id)、index.FilterField(title)以及标签相关字段声明了可检索/可过滤字段。对应测试见 test_listing.py 的test_search_by_title、test_order_by_title、test_filter_by_title与test_listing_prefetches_tags后者验证列表查询会预取 tags避免 N1。上传文档multipart/form-data 与完整校验链POST /documents/用于创建文档要求认证请求且拥有文档add权限。请求使用multipart/form-data格式file字段携带文档二进制内容可写的元数据以独立表单字段发送curl -X POST https://example.com/api/v3/documents/ \ -H Authorization: Bearer $TOKEN \ -F filepolicy.pdf \ -F titleAcceptable use policy \ -F collection_id3其中title与file是必填字段。源码中create_documentrouter.py将file作为UploadedFile、其余字段作为DocumentCreateSchemaForm(...)接收然后通过build_document_form构造表单、经动作注册表action_registry取得文档的create动作并执行。上传走的正是管理后台的同一套表单与校验。关键实现在 wagtail/documents/api/v3/form_data.pybuild_document_form使用get_document_form(model)获取活动文档模型的表单类把 API payload 转换为表单数据并传入上传用户写入uploaded_by_user。这意味着集合权限校验用户只能把文档上传到自己有add权限的集合否则表单校验失败返回 422。当用户只有单个可上传集合且未显式指定时_restore_hidden_collection_field会自动补全该集合扩展名限制WAGTAILDOCS_EXTENSIONS设置项会限制允许的扩展名源码实现在 wagtail/documents/models.py 的Document.clean()通过 Django 的FileExtensionValidator校验。对应测试见 test_api_v3/test_create.py 的test_bad_extension_returns_422文件大小限制WAGTAILDOCS_MAX_UPLOAD_SIZE控制最大上传字节数由 wagtail/documents/fields.py 中的WagtailDocumentField校验超限同样返回 422测试test_oversized_file_returns_422。文档明确警告扩展名校验只检查文件名并不验证文件内容与扩展名是否匹配。因此对不受信任的上传内容还应结合项目自身的上传安全策略如存储后端、杀毒扫描等进行处理。创建成功返回 HTTP 201 与完整的文档 JSON 详情。权限与校验失败的典型响应包括匿名请求 401test_anonymous_returns_401、无add权限 403test_user_without_add_permission_gets_403、缺少必填字段或集合越权 422test_missing_title_returns_422、test_missing_file_returns_422、test_forbidden_collection_returns_422。更新元数据JSON PATCH 与不可写字段PATCH /documents/{id}/以 JSON 格式更新文档的可写元数据要求认证请求和文档change权限curl -X PATCH https://example.com/api/v3/documents/7/ \ -H Authorization: Bearer $TOKEN \ -H Content-Type: application/json \ -d {title: Acceptable use policy (revised)}两个重要的限制需要牢记更新不能替换文档的原始二进制文件——文件本体只能在创建时上传tags 不能通过文档 API 写入。在源码层面update_documentrouter.py接收DocumentPatchSchemaBody(...)通过build_document_update_form构造更新表单它只对请求中实际出现的字段exclude_unsetTrue构造表单从而天然支持部分更新——未提交的字段保持原值。对应的 test_update.py 中的test_partial_update_leaves_collection_and_file_unchanged正是验证这一点。此外把文档移动到无权访问的集合会返回 422test_update_to_forbidden_collection_returns_422匿名请求返回 401test_anonymous_returns_401。删除文档硬删除与文件清理DELETE /documents/{id}/删除文档要求认证请求和文档delete权限。文档明确指出删除是硬删除hard delete且删除过程会一并清理对应的物理文件。实现上router.py通过动作注册表执行文档的delete动作并返回 204。相关测试见 test_delete.pytest_superuser_can_delete、test_user_without_delete_permission_gets_403、test_uploader_with_add_permission_can_delete_own_document上传者凭add权限可删除自己的文档以及test_stored_file_is_deleted_on_commit提交时删除存储文件。curl -X DELETE https://example.com/api/v3/documents/7/ \ -H Authorization: Bearer $TOKEN自定义文档模型API 自动跟随如果项目通过WAGTAILDOCS_DOCUMENT_MODEL启用了自定义文档模型完整指南见 docs/advanced_topics/documents/custom_document_model.mdv3 API 会自动基于该活动模型工作生成的上传/更新 schema 与表单会包含自定义模型的 API 字段api_fields和管理后台字段admin_form_fields并应用其自定义表单校验。从 wagtail/documents/api/v3/schemas.py 可以看到创建/更新 schema 的字段集合来自Document.admin_form_fields排除file与tags这意味着自定义模型在admin_form_fields中追加的字段会直接出现在 API 的可写字段中。定义自定义模型的方式摘自 custom_document_model.md# models.py from django.db import models from wagtail.documents.models import Document, AbstractDocument class CustomDocument(AbstractDocument): # Custom field example: source models.CharField(max_length255, blankTrue, nullTrue) admin_form_fields Document.admin_form_fields ( # Add all custom field names to make them appear in the form: source, )# settings.py — 将 app_label 替换为自定义模型所在应用 WAGTAILDOCS_DOCUMENT_MODEL app_label.CustomDocument专项测试 test_custom_document_model.py 覆盖了自定义模型的读取、创建、更新与 schema 生成test_create_schema_includes_custom_admin_form_fields、test_patch_schema_includes_custom_admin_form_fields、test_document_input_schemas_include_writable_api_fields、test_create_action_saves_custom_document_and_metadata、test_custom_model_unique_constraint_returns_form_error自定义唯一约束冲突时以表单错误形式返回以及test_configured_base_form_validation_is_used自定义基类表单校验生效。综合示例上传文档并在页面富文本中引用文档最后给出了一个完整闭环示例上传文档 → 读回确认 → 创建页面并在富文本正文中以文档引用wagtail://document链接到该文档。示例假设BASE指向已挂载的 API 根地址TOKEN为 Bearer Token。第一步上传文件并捕获返回的文档 ID响应即为创建端点的完整 JSON 详情curl -X POST $BASE/documents/ \ -H Authorization: Bearer $TOKEN \ -F filepolicy.pdf \ -F titleAcceptable use policy第二步读回文档确认已存储curl $BASE/documents/7/第三步创建页面在富文本正文中使用wagtail://document引用链接到该文档使用 docs/advanced_topics/api/v3/rich_text.md 中描述的富文本输入格式curl -X POST $BASE/pages/ \ -H Authorization: Bearer $TOKEN \ -H Content-Type: application/json \ -d { meta: {type: blog.BlogPage, parent_id: 3}, title: Example, body: { format: db_markdown, content: Important notices: our policy. } }富文本的输入格式在 rich_text.md 中有详细说明写入时顶层页面富文本字段可接受纯字符串数据库 HTML会按字段声明的 features 做净化或{format: ..., content: ...}信封对象支持的输入格式包括db_html默认与db_markdown。db_markdown使用wagtail://引用语法Markdown 会被转换并净化后以数据库 HTML 形式存储。需要留意的是净化会静默移除字段 features 不允许的内容响应中可能出现比提交内容更少的情况。参考完整的 OpenAPI 文档v3 API 为每个文档端点生成了完整、可交互的 OpenAPI 参考——包括请求与响应结构。在你自己的部署中可以直接访问项目自生成的交互式文档OpenAPI JSONAPI root/openapi.json交互式文档API root/docs/这两个路由默认公开可用若想增加一层隐匿性可通过WAGTAILAPI_DOCS_ENABLED False同时禁用相关逻辑见 wagtail/api/v3/api.py 的_gate_docs装饰器测试见 wagtail/api/v3/tests/test_docs.py。本仓库自带的 OpenAPI 快照位于 wagtail/api/v3/tests/snapshots/openapi.json仓库文档中的参考章节即由它渲染见 docs/advanced_topics/api/v3/reference.md对于真实部署应以自己项目实时生成的/docs/与openapi.json为准。【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表