5

我想实现这样的目标,

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())
    ])

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

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

4

1 回答 1

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 可以包含可以包含 ThirdLevelCarousel 块的 SecondLevelCarousel 块,但仅此而已),或者想出一个替代数据表示将数据条目分布在多个视图中,而不是单个无限嵌套的表单。例如,您可以将 Carousel 和 Tab 定义为片段模型,并使用 SnippetChooserBlock 定义它们之间的父/子链接:

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

(当然,如果你沿着这条路走,你必须确保不要建立任何循环的父/子关系,否则你会回到第一方:-))

于 2016-06-16T19:07:19.693 回答