如何在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
相关产品推荐
相关产品推荐

