【问题标题】:Wagtail Page title overwriting鹡鸰页面标题覆盖
【发布时间】:2018-02-05 15:22:33
【问题描述】:

我上面有这个模型,我想删除标题。或者重命名。实际上比赛号码本身就是这个模型的标题。所以我需要以下选项之一:

  • 将标题重命名为“匹配编号”
  • 将自定义帮助文本添加到标题“添加匹配数”
  • 删除标题

我的模特:

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"),
    ]

【问题讨论】:

    标签: python wagtail


    【解决方案1】:

    实现此目的的一种方法是从content_panels 中实际删除title。然后在 Page 的 clean 方法中手动创建 titleslug 字段。您还需要为您的模型设置默认的 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)。编辑界面还在客户端(在 Javascript 中)构建 slug 字段,它依赖于存在的 title 字段。

    因此,您必须自己处理生成titleslug 字段。重要的是 slug 字段既是独特的又是 slugified。

    在示例代码中,没有考虑编辑器自己手动设置 slug(在提升面板中),无论用户将 slug 设置为什么,它都将始终覆盖为 match-123

    title 字段可以是任何字符串,但是是必需的。

    请记住,Wagtail 并没有规定您如何以任何方式使用 title 字段来呈现模板。实际上只有模型限制和管理界面假定存在标题。

    Wagtail Github 页面上有一个关于这个项目的旧讨论:https://github.com/wagtail/wagtail/issues/161

    代码精挑细选

    • 合理的约定是以MySomethingPage 格式命名您的页面模型,并在末尾加上Page,这有助于您和其他开发人员知道这是一个页面。
    • 您的字段不需要以页面的模型名称为前缀(例如match_somethingmatch_other_thing)。这会让人感到困惑,因为当match_page.number 更直观时,您将不得不输入match_page.match_number。或者,如果您确实使用此约定,请在每个字段上使用它,例如 match_page.match_team_1
    • 在您的代码中,您要手动创建多个团队,通过相关模型和InlinePanel 来探索这样做可能会更好,这意味着代码重复会大大减少。请参阅有关 InlinePanels & Model Clusters 的文档

    【讨论】:

    • 非常感谢@LB Ben Johnston 的帮助和我的代码审查 :) 我会检查它,然后选择正确答案。我有ForeignKey 可以从另一个模型中获取团队,但我会检查它如何与cluster 一起工作
    • 最后一行MatchPage._meta.get_field('slug').default = 'default-blank-slug' 的副作用是为Page 模型设置默认值slug,这意味着对于您不希望设置标题的所有模型自动,您必须在编辑时手动清除 slug。
    • 我发现表单验证在标题的编程设置执行之前被激活。因此,我们最终会出现“必填字段”错误。 slug的设置也是在Page的full_clean中进行的。
    【解决方案2】:

    要解决@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。您可能不希望这样 - 但您可以根据需要调整代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-22
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多