Wagtail 页面标题覆盖
Wagtail Page title overwriting
我上面有这个模型,我想去掉标题。或者重命名它。其实比赛号码本身就是这个型号的名称。所以我需要以下选项之一:
- 将标题重命名为 "Match Number"
- 向标题添加自定义帮助文本"Add a Number of Match"
- 删除标题
我的模型:
class Match(Page):
match_number = models.PositiveSmallIntegerField(blank=True)
team_1 = models.ForeignKey(
TeamRooster,
null=True, blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
team_1_color = ColorField(default='#ff0000', blank=True)
team_1_score = models.PositiveSmallIntegerField(blank=True)
team_2 = models.ForeignKey(
TeamRooster,
null=True, blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
team_2_color = ColorField(default='#0066ff', blank=True)
team_2_score = models.PositiveSmallIntegerField(blank=True)
match_starts_at = models.DateTimeField()
parent_page_types = ['Matches']
content_panels = [
FieldPanel('title'),
FieldPanel('match_number', classname="6"),
FieldPanel('match_starts_at', classname="6"),
MultiFieldPanel([
FieldPanel('team_1', classname="12"),
FieldPanel('team_1_color', classname="6"),
FieldPanel('team_2_score', classname="6"),
], heading="Team 1"),
MultiFieldPanel([
FieldPanel('team_2', classname="12"),
FieldPanel('team_2_color', classname="6"),
FieldPanel('team_2_score', classname="6"),
], heading="Team 2"),
]
实现此目的的一种方法是实际从 content_panels
中删除 title
。然后在主页的 clean
方法中手动创建 title
和 slug
字段。您还需要为模型设置默认 slug
值。
例子
from django.utils.text import slugify
# all other imports (Page, models, panels etc)
class MatchPage(Page):
"""A page that represents a single game match."""
number = models.IntegerField(
unique=True, # must be unique for use in slug
help_text="Add the unique number of this Match.")
starts_at = models.DateTimeField(
blank=True, # allows blank values (ie. not required)
help_text="Date and time of when this Match starts.")
content_panels = [
# title not present, title should NOT be directly editable
MultiFieldPanel([
FieldRowPanel([
FieldPanel('number', classname="col6"),
FieldPanel('starts_at', classname="col6"),
]),
], 'Match'),
# other field panels... teams etc
]
def clean(self):
"""Override the values of title and slug before saving."""
# super(MatchPage, self).clean() # Python 2.X syntax
super().clean()
new_title = 'Match %s' % self.number
self.title = new_title
self.slug = slugify(new_title) # slug MUST be unique & slug-formatted
# set a default blank slug for when the editing form renders
# we set this after the model is declared
MatchPage._meta.get_field('slug').default = 'default-blank-slug'
详情
这可能是 Wagtail 的一个令人困惑的问题,因为 Page
模型(与您的 MatchPage
模型分开)必须具有某些字段(标题、slug)。编辑界面还在客户端构建 slug 字段(在 Javascript 中),它依赖于存在的 title
字段。
因此您必须自己负责生成 title
和 slug
字段。重要的是 slug 字段既是唯一的又是 slugified 的。
在示例代码中没有考虑编辑器自己手动设置 slug(在 Promote 面板中),无论用户将 slug 设置为什么,它总是会覆盖 match-123
。
title
字段可以是任何字符串,但这是必需的。
请记住,Wagtail 不会规定您如何以任何方式使用 title
字段来呈现模板。只有模型限制和管理界面假定存在标题。
在 Wagtail Github 页面上有一个关于这个项目的旧的和持续的讨论:https://github.com/wagtail/wagtail/issues/161
代码挑剔
- 以
MySomethingPage
格式命名页面模型并在末尾添加 Page
是一个合理的约定,这有助于您和其他开发人员知道这是一个页面。
- 您的字段不需要以页面的型号名称为前缀(例如
match_something
或 match_other_thing
)。这会让你在路上感到困惑,因为当 match_page.number
更直观时,你必须输入 match_page.match_number
。或者,如果您确实使用此约定,请在每个字段上使用它,例如 match_page.match_team_1
.
- 在您的代码中,您正在手动创建多个 团队 ,通过相关模型和
InlinePanel
探索这样做可能会更好,这将意味着更少的重复的代码。请参阅有关 InlinePanels & Model Clusters 的文档
要解决 @Mark Chackerian 发现的问题,您可以为 wagtail
页面定义自定义 base_form_class
。
现在,您可以挂接到自定义表单的 save
方法,而不是覆盖模型的 clean 函数。因此,您不必为 EVERY wagtail 页面设置默认 slug:
forms.py
:
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 not self.initial['title']:
self.initial['title'] = _('auto-generated-title')
if not self.initial['slug']:
self.initial['slug'] = _('auto-generated-slug')
def save(self, commit=True):
page = super().save(commit=False)
new_title = strip_tags(self.cleaned_data['rtf_title'])
page.title = new_title
page.slug = slugify(new_title)
if commit:
page.save()
return page
models.py
:
# ... imports omitted for brevity
class PageWithRtfTitle(Page):
base_form_class = NoTitleForm
rtf_title = RichTextField()
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel('rtf_title'),
],
heading=_('Metadata')
)]
# ...
不过,对于某些用例,此解决方案可能并不理想。每次标题更改时,这两种方法都会覆盖 slug。您可能不希望这样 - 但您可以根据需要调整代码。
我上面有这个模型,我想去掉标题。或者重命名它。其实比赛号码本身就是这个型号的名称。所以我需要以下选项之一:
- 将标题重命名为 "Match Number"
- 向标题添加自定义帮助文本"Add a Number of Match"
- 删除标题
我的模型:
class Match(Page):
match_number = models.PositiveSmallIntegerField(blank=True)
team_1 = models.ForeignKey(
TeamRooster,
null=True, blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
team_1_color = ColorField(default='#ff0000', blank=True)
team_1_score = models.PositiveSmallIntegerField(blank=True)
team_2 = models.ForeignKey(
TeamRooster,
null=True, blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
team_2_color = ColorField(default='#0066ff', blank=True)
team_2_score = models.PositiveSmallIntegerField(blank=True)
match_starts_at = models.DateTimeField()
parent_page_types = ['Matches']
content_panels = [
FieldPanel('title'),
FieldPanel('match_number', classname="6"),
FieldPanel('match_starts_at', classname="6"),
MultiFieldPanel([
FieldPanel('team_1', classname="12"),
FieldPanel('team_1_color', classname="6"),
FieldPanel('team_2_score', classname="6"),
], heading="Team 1"),
MultiFieldPanel([
FieldPanel('team_2', classname="12"),
FieldPanel('team_2_color', classname="6"),
FieldPanel('team_2_score', classname="6"),
], heading="Team 2"),
]
实现此目的的一种方法是实际从 content_panels
中删除 title
。然后在主页的 clean
方法中手动创建 title
和 slug
字段。您还需要为模型设置默认 slug
值。
例子
from django.utils.text import slugify
# all other imports (Page, models, panels etc)
class MatchPage(Page):
"""A page that represents a single game match."""
number = models.IntegerField(
unique=True, # must be unique for use in slug
help_text="Add the unique number of this Match.")
starts_at = models.DateTimeField(
blank=True, # allows blank values (ie. not required)
help_text="Date and time of when this Match starts.")
content_panels = [
# title not present, title should NOT be directly editable
MultiFieldPanel([
FieldRowPanel([
FieldPanel('number', classname="col6"),
FieldPanel('starts_at', classname="col6"),
]),
], 'Match'),
# other field panels... teams etc
]
def clean(self):
"""Override the values of title and slug before saving."""
# super(MatchPage, self).clean() # Python 2.X syntax
super().clean()
new_title = 'Match %s' % self.number
self.title = new_title
self.slug = slugify(new_title) # slug MUST be unique & slug-formatted
# set a default blank slug for when the editing form renders
# we set this after the model is declared
MatchPage._meta.get_field('slug').default = 'default-blank-slug'
详情
这可能是 Wagtail 的一个令人困惑的问题,因为 Page
模型(与您的 MatchPage
模型分开)必须具有某些字段(标题、slug)。编辑界面还在客户端构建 slug 字段(在 Javascript 中),它依赖于存在的 title
字段。
因此您必须自己负责生成 title
和 slug
字段。重要的是 slug 字段既是唯一的又是 slugified 的。
在示例代码中没有考虑编辑器自己手动设置 slug(在 Promote 面板中),无论用户将 slug 设置为什么,它总是会覆盖 match-123
。
title
字段可以是任何字符串,但这是必需的。
请记住,Wagtail 不会规定您如何以任何方式使用 title
字段来呈现模板。只有模型限制和管理界面假定存在标题。
在 Wagtail Github 页面上有一个关于这个项目的旧的和持续的讨论:https://github.com/wagtail/wagtail/issues/161
代码挑剔
- 以
MySomethingPage
格式命名页面模型并在末尾添加Page
是一个合理的约定,这有助于您和其他开发人员知道这是一个页面。 - 您的字段不需要以页面的型号名称为前缀(例如
match_something
或match_other_thing
)。这会让你在路上感到困惑,因为当match_page.number
更直观时,你必须输入match_page.match_number
。或者,如果您确实使用此约定,请在每个字段上使用它,例如match_page.match_team_1
. - 在您的代码中,您正在手动创建多个 团队 ,通过相关模型和
InlinePanel
探索这样做可能会更好,这将意味着更少的重复的代码。请参阅有关 InlinePanels & Model Clusters 的文档
要解决 @Mark Chackerian 发现的问题,您可以为 wagtail
页面定义自定义 base_form_class
。
现在,您可以挂接到自定义表单的 save
方法,而不是覆盖模型的 clean 函数。因此,您不必为 EVERY wagtail 页面设置默认 slug:
forms.py
:
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 not self.initial['title']:
self.initial['title'] = _('auto-generated-title')
if not self.initial['slug']:
self.initial['slug'] = _('auto-generated-slug')
def save(self, commit=True):
page = super().save(commit=False)
new_title = strip_tags(self.cleaned_data['rtf_title'])
page.title = new_title
page.slug = slugify(new_title)
if commit:
page.save()
return page
models.py
:
# ... imports omitted for brevity
class PageWithRtfTitle(Page):
base_form_class = NoTitleForm
rtf_title = RichTextField()
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel('rtf_title'),
],
heading=_('Metadata')
)]
# ...
不过,对于某些用例,此解决方案可能并不理想。每次标题更改时,这两种方法都会覆盖 slug。您可能不希望这样 - 但您可以根据需要调整代码。