使用 StreamBlock 时如何解决 Wagtail 循环块依赖性

Mev*_*abu 5 python django wagtail wagtail-streamfield

我想实现这样的目标,

from wagtail.wagtailcore.blocks import StreamBlock, StructBlock


class CarouselBlock(StructBlock):

    content = StreamBlock([
        ('tab', TabBlock()),
        ('carousel', CarouselBlock())
    ])


class TabBlock(StructBlock):

    content = StreamBlock([
        ('tab', TabBlock()),
        ('carousel', CarouselBlock())
    ])
Run Code Online (Sandbox Code Playgroud)

在轮播中,我可以添加一个选项卡或另一个轮播,在选项卡中我可以添加一个轮播或另一个选项卡。

处理此类编程案例的最佳实践是什么。

gas*_*man 5

不幸的是,即使您找到了在定义中设置循环引用的方法,我也不认为有可能完成这项工作。Wagtail 的代码中有很多地方会尝试将定义作为树遍历,并以无限递归结束。

例如,在迁移中冻结 StreamField 定义时会发生这种情况 - 它会将任何对命名 StructBlock / StreamBlock 子类的引用扩展为普通的 StructBlock / StreamBlock 构造函数(请参阅http://docs.wagtail.io/en/v1.5.2/topics /streamfield.html#streamfield-definitions-within-migrations),在这种情况下会无限扩展。类似地,为编辑表单构建 HTML 将失败,因为它将尝试为表单中的每个可重复元素构建一个 HTML 模板(即每当您单击以添加新轮播或新选项卡时要添加的 HTML 块) - 而且对于顶级轮播、二级轮播、三级轮播等重复使用相同的模板是不够聪明的,因此将生成无限数量的模板。

您要么需要对嵌套级别的数量进行硬编码限制(例如 CarouselBlock 可以包含一个 SecondLevelCarousel 块,该块可以包含一个 ThirdLevelCarousel 块,但不能更多),或者想出一个替代数据表示将数据条目分布在多个视图中,而不是单个无限嵌套的表单中。例如,您可以将 Carousel 和 Tab 定义为片段模型,并使用 SnippetChooserBlock 定义它们之间的父/子链接:

@register_snippet
class Carousel(models.Model):
    content = StreamField([
        ('carousel', blocks.SnippetChooserBlock('myapp.Carousel')),
        ('tab', blocks.SnippetChooserBlock('myapp.Tab')),
    ])
Run Code Online (Sandbox Code Playgroud)

(当然,如果你走这条路,你必须确保不要建立任何循环的父/子关系,否则你又回到了原点:-))