【问题标题】:Wagtail many-to-many links between different Page modelsWagtail 不同页面模型之间的多对多链接
【发布时间】:2021-02-01 22:06:01
【问题描述】:

是否有人拥有或知道在不同页面模型之间设置多对多关系的方法(示例代码和/或说明)?如果我有 PersonPage 和 SitePage 模型,我如何连接页面(一个人可以在多个站点工作,一个站点可以有多个人在那里工作)?

这是我发现的与该主题相关但不直接相关的内容——

  • Wagtail 文档:通过搜索“多对多”,only hit 位于 taggit 模块(食谱页面)的部分中。

  • Wagtail 文档:the only reference 到 ParentalManyToManyField 演示了如何使用它在页面和类别之间创建 M2M(教程)

  • This 2015 post 关于 Wagtail 中的 M2M 关系(在 an SO 'answer' 中引用了我在这里问的基本相同的问题)。虽然它没有讨论页面-页面关系,但所提出的方法可能适用于工作。根据我尝试设置 InlinePanel 调用的方式,我修改后的模仿失败并出现各种错误 - 但帖子中的示例代码以同样的方式失败,因此要么没有经过测试,要么在 2.x 中已过时。

    class PersonPage(Page):
        pass
    
    PersonPage.content_panels =  [
        InlinePanel('ps_links', label='PS Links'), 
    ]   
    
    class PersonSitePageLink():
        spage = models.ForeignKey('SitePage', on_delete=models.SET_NULL, related_name='sites')
        ppage = ParentalKey('PersonPage', related_name='ps_links', on_delete=models.SET_NULL,)
        panels = [
            FieldPanel('spage')
        ]

    class SitePage(Page):
        pass
  • This technique 可以很好地将 Page 模型与其自身相关联,但将其扩展为包含两个不同的模型会创建两个平行但未连接的关系集(您可以选择任意 Bug 页面链接到任何 Plant 页面,反之亦然,但 Plants编辑错误时选择的不显示)。我想我在代码中明白了原因,但我不明白如何在两个页面之间建立单个 M2M 连接。
    class PlantPage(Page):
        related_bugs = ParentalManyToManyField('BugPage', blank=True)
        content_panels = Page.content_panels + [
            FieldPanel('related_bugs'),
        ]   

    class BugPage(Page):
        related_plants = ParentalManyToManyField('PlantPage', blank=True)
        content_panels = Page.content_panels + [
            FieldPanel('related_plants'),
        ]   
  • This one 也只讨论页内模型(而不是页间模型)M2M。 (它是先于 ParentalManyToManyField 的,实际上只能从 Wayback Machine 获得。)

【问题讨论】:

    标签: wagtail


    【解决方案1】:

    我希望这会有所帮助,我从这篇文章中获得了关于从 ParentalManyToManyField 转移到一个中心模型的灵感,该模型“链接”来自这个 AccordBox article 的每个页面。

    事实证明InlinePanel 不完全支持ParentalManyToManyField,因此您遇到了问题。

    我能够为您的上述选项实施一种改进的方法,它应该可以解决您的问题。

    提醒一下,所有 Page 模型都已扩展 ClusterableModel,因此无需将其添加到您创建的任何模型中。

    概述

    • 创建一个扩展 models.Model 的新“关系”,这将是这两个页面模型之间的关系。
    • 这个新模型中的每个字段都将是通过模型集群ParentalKey 的两种页面类型,每一种都有一个逻辑related_name 集,即关系的另一端。
    • 无需在此模型上设置panels,因为我们将通过panels kwarg 到InlinePanel 单独声明面板 - 请参阅InlinePanel docs。
    • 最后,每个Page 的content_panels 添加了一个InlinePanel,通过该模型的related_name 间接引用中心关系模型,并将另一侧引用添加到PageChooserPanel。

    示例代码

    
    from modelcluster.fields import ParentalKey
    from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, PageChooserPanel
    
    class PersonPageSitePageRelation(models.Model):
        person = ParentalKey('app.PersonPage', on_delete=models.CASCADE, related_name='sites')
        site = ParentalKey('app.SitePage', on_delete=models.CASCADE, related_name='people')
        # Optional: some additional fields (e.g. 'note') for this relation
        # Important: NOT setting any `panels` here, will be set individually for each 'direction'
    
        class Meta:
            unique_together = ('person', 'site')
    
    
    class PersonPage(Page):
        # ... fields (note: `sites` does NOT need to be declared as a field)
        
        # Now we add an `InlinePanel` that will connect to the parental connection to PersonPageSitePageRelation via the related name `sites`, but the panels available will be the PersonPageSitePageRelation's field `site`
        content_panels = Page.content_panels + [
            # ... other FieldPanel etc
            InlinePanel('sites', label='Related Sites', [PageChooserPanel('site')]),
        ]
    
    
    class SitePage(Page):
        # ... fields (note: `people` does NOT need to be declared as a field)
    
        # Now we add an `InlinePanel` that will connect to the parental connection to PersonPageSitePageRelation via the related name `people`, but the panels available will be the PersonPageSitePageRelation's field `person`
        content_panels = Page.content_panels + [
            # ... other FieldPanel etc
            InlinePanel('people', label='Related People', panels=[PageChooserPanel('person')]),
        ]
    

    进一步阅读

    【讨论】:

    • 这个答案有效!您可以从关系任一侧的页面开始,然后选择(添加为相关)另一个模型的页面(任意数量)。当您编辑任何这些相关页面时,您开始的页面现在显示为相关的,正如预期的那样。我将两种页面类型的 PageChooserPanels 添加到“通过”模型(在上面的示例中为“PersonPageSitePageRelation”)并将该模型注册为 sn-p。这使您可以查看和编辑相关的页面对,但一次只能一对 - 不确定这是否很有帮助。
    • 还有待解决:如何过滤您在添加相关页面时看到的页面列表,以排除您已经添加/设置为相关的页面。
    • 嗨琼。以这种方式过滤 PageChooserPanel 可用的选项可能并不容易。但是唯一的共同约束应该阻止用户实际保存完全相同的关系对。
    • 那么我们应该在这里休息并依靠“独一无二”,直到至少我们完成了许多更高优先级的待办事项。感谢您的来信。
    猜你喜欢
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    相关资源
    最近更新 更多