You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Wagtail中生成含数据库ID的PersonPage自定义Slug?

解决Wagtail PersonPage生成surname-name-id格式slug的问题

问题背景

需要创建无title字段的Wagtail PersonPage,包含surname和name字段,保存时自动生成格式为surname-name-id的slug(id为数据库主键)。当前已通过自定义表单移除title字段,但无法在保存时获取数据库ID来生成目标slug。

核心问题

新建页面时,数据库主键ID仅在页面首次保存后才会生成,因此无法在表单的save方法中直接获取ID生成slug。

解决方案

通过重写PersonPage模型的save方法,分两步完成页面保存与slug更新:先保存页面获取ID,再基于ID生成并更新slug。同时修正表单与模型的细节问题。

1. 修正自定义表单NoTitleForm

简化表单逻辑,仅禁用title和slug字段,根据页面状态设置初始值:

from django import forms
from django.utils.translation import gettext_lazy as _
from django.utils.text import slugify
from django.utils.html import strip_tags
from wagtail.admin.forms import WagtailAdminPageForm


class NoTitleForm(WagtailAdminPageForm):
    title = forms.CharField(required=False, disabled=True, help_text=_('Title is auto-generated.'))
    slug = forms.SlugField(required=False, disabled=True, help_text=_('Slug is auto-generated.'))

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 新建页面时设置占位初始值,编辑时显示已生成的内容
        if self.instance.id is None:
            self.initial['title'] = _('auto-generated-title')
            self.initial['slug'] = _('auto-generated-slug')
        else:
            surname_clean = strip_tags(self.instance.surname)
            name_clean = strip_tags(self.instance.name)
            self.initial['title'] = f"{surname_clean} {name_clean}"
            self.initial['slug'] = slugify(f"{surname_clean}-{name_clean}-{self.instance.id}")

2. 重写PersonPage模型的save方法

移除模型中重复的字段面板,并重写save方法实现分阶段保存与slug更新:

from django.utils.text import slugify
from django.utils.html import strip_tags
from wagtail.models import Page
from wagtail.admin.panels import MultiFieldPanel, FieldPanel
from django.utils.translation import gettext_lazy as _


class PersonPage(Page):
    surname = RichTextField()
    name = RichTextField()
    base_form_class = NoTitleForm

    # 修正原代码中重复的surname字段面板
    content_panels = [
        MultiFieldPanel(
            [
                FieldPanel('surname'),
                FieldPanel('name'),
            ],
            heading=_('Metadata')
        )
    ]

    def save(self, *args, **kwargs):
        is_new_page = self.id is None
        
        # 第一步:保存页面,获取数据库主键ID
        super().save(*args, **kwargs)
        
        # 第二步:仅在新建页面时更新slug和title
        if is_new_page:
            surname_clean = strip_tags(self.surname)
            name_clean = strip_tags(self.name)
            
            # 生成目标格式的slug
            target_slug = slugify(f"{surname_clean}-{name_clean}-{self.id}")
            # 生成对应的title
            target_title = f"{surname_clean} {name_clean}"
            
            # 使用update方法避免递归调用save
            PersonPage.objects.filter(id=self.id).update(
                slug=target_slug,
                title=target_title
            )

关键说明

  • 分阶段保存:先调用父类save方法获取ID,再基于ID生成slug,解决新建页面时无ID的问题。
  • 使用objects.update而非再次调用save:避免递归触发save方法导致循环。
  • 表单优化:编辑页面时自动显示已生成的title和slug,提升后台操作体验。

内容的提问来源于stack exchange,提问作者Ofelus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 11:07:03