【问题标题】:Get parent page on creating new Wagtail Page获取有关创建新 Wagtail 页面的父页面
【发布时间】:2023-03-03 20:05:01
【问题描述】:

在创建新页面时,我需要根据父页面的值更改某些字段默认值。在编辑现有页面时,这不是问题,但是在创建新页面时,我需要为字段设置默认值。我尝试覆盖管理表单,在 WagtailAdminPageForm 的 init 上,parent_page 参数为空。如果我尝试在页面子类的 init 方法表单上执行此操作,则没有带有父信息的 arg 或 kwargs。

有没有办法获取新页面将成为父页面的页面?

这是我在页面构造函数上尝试的

class CMSPage(Page):
    .
    .
    .
    def __init__(self, *args, **kwargs):
        super(BaseContentMixin, self).__init__(*args, **kwargs)

        if hasattr(self.get_parent().specific, 'published_site') and self.get_parent().specific.published_site == 'extranet':
            self.published_site = 'extranet'

这适用于编辑页面,对于新页面,我知道 NoneType 对象没有特定的属性。

Django 版本是 1.10,Python 版本是 3.6,Wagtail 版本是 1.9

【问题讨论】:

    标签: python django wagtail


    【解决方案1】:

    在澄清问题后,这是第二个可能更合适的答案。请注意,这需要 Wagtail 1.11.x,目前尚未发布。

    解决方案示例代码

    首先为您的自定义页面表单创建一个新类,通常在 models.py 或您页面的模型所在的任何位置。

    from wagtail.wagtailadmin.forms import WagtailAdminPageForm
    
    class MyCustomPageForm(WagtailAdminPageForm):
    
        # Override the __init__ function to update 'initial' form values
        def __init__(self, data=None, files=None, parent_page=None, *args, **kwargs):
            print('parent_page', parent_page, parent_page.id, parent_page.title)
            # update the kwargs BEFORE the init of the super form class
            instance = kwargs.get('instance')
            if not instance.id:
                # only update the initial value when creating a new page
                kwargs.update(initial={
                    # 'field': 'value'
                    'title': parent_page.id  # can be anything from the parent page
                })
            # Ensure you call the super class __init__
            super(MyCustomPageForm, self).__init__(data, files, *args, **kwargs)
            self.parent_page = parent_page
    

    第二在页面模型定义上,告诉该模型使用你定义的表单类

    from wagtail.wagtailcore.models import Page
    
    class MyCustomPage(Page):
        base_form_class = MyCustomPageForm
    

    解决方案说明

    • Wagtail 提供了覆盖在 Wagtail Admin 中构建用于创建和编辑的表单时调用的表单类(注意:不是模型类)的能力。
    • 文档:Customising generated forms
    • 我们的自定义表单类将继承WagtailAdminPageForm 类。
    • 在这个新的表单类中,我们要定义自己的__init__ 函数,该函数在表单创建时调用。
    • 注意default definition of __init__ on WagtailAdminPageForm 的 Github 代码
    • 为了注入自定义值,我们将在调用类'super __init__之前覆盖kwargs中的initial数据
    • 我们只想在创建新页面时执行此操作,因此请检查该实例是否没有id
    • 我们可以访问parent_page 实例及其中的任何字段
    • 添加自定义初始数据后,我们使用更改后的 kwargs 调用 super __init__
    • 注意:Wagtail 1.11.x 要求的原因是之前的版本在调用类模型时没有添加 parent_page 直到pull request 3508

    【讨论】:

      【解决方案2】:

      我建议使用 Wagtail Hooks:

      http://docs.wagtail.io/en/v1.10.1/reference/hooks.html

      这是一个有效的基本示例(在 Wagtaildemo 应用程序中),在此示例中,我只是获取父页面的标题。如果您从父页面的特定模型中获取其他内容,它应该可以正常工作。请注意,这会在创建后更新记录,而不是作为创建本身的一部分。

      # my_app/wagtail_hooks.py
      from wagtail.wagtailcore.models import Page
      from wagtail.wagtailcore import hooks
      
      
      @hooks.register('after_create_page')
      def do_after_page_create(request, page):
          # get the parent page from the current page
          parent = page.get_parent().specific
          # get the value from the parent page
          parent_title = parent.title
          # get a new instance of the page that was just created
          new_page = Page.objects.get(id=page.id).specific
          # update the value in the page that was just created & save
          new_page.parent_title = parent_title
          new_page.save()
      

      我经常使用 Wagtail 钩子,它们运行良好,您可以通过检查 new_page.content_type == "CMSPage" 来进一步完善它,以确保这只更新该特定模型的页面。

      最后,看看 Wagtail 网站的工作原理可能会很好,这可能是示例代码中针对您的问题的更具体的解决方案。您可以添加额外的settings to your Site Model 并拥有multiple Sites in Wagtail。我不确定您的示例只是一个粗略的示例还是您面临的确切问题。

      【讨论】:

      • @Ib ben johnston 感谢您的回答,但是,我想要实现的是更改表单字段的默认值,具体取决于父页面中的某些属性。保存后不更新页面。还是谢谢
      • @Cheluis 这是否更好地解释了您的用例?只是试图理解。 1. 用户加载表单页面(填写表单)。 2. 默认字段值(例如下拉框),通常设置为列表中的第一个值。 3. 覆盖行为是根据Form的父页面设置值。注意:我之前已经覆盖了默认表单值(基于 URL 查询变量),所以我可能会建议一种方法来做到这一点。
      • 不,我的情况是当您添加一个作为另一个页面的子页面的新页面时,我想在它的创建表单上捕获它的父页面,而不是在它创建之后。我需要根据父字段值在创建表单上设置一个值
      • @Cheluis 看起来您也标记了我在 wagtail 代码库中遇到的类似问题,并且似乎在最新的 1.11 版本中修复了该问题,应该很快就会发布。我创建了一个新答案,因为原始答案可能对某些人仍然有用。我希望这会有所帮助。
      • @Ib ben Johnston,是的,我尝试了您的方法,但出于同样的原因,我无法获取父页面实例。感谢您的帮助
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多