我想实现这样的目标,
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())
])
在旋转木马中,我可以添加标签或其他旋转木马,在标签内我可以添加旋转木马或其他标签。
处理类似这样的编程案例的最佳做法是什么。
答案 0 :(得分:4)
不幸的是,即使您找到了在定义中设置循环引用的方法,我也不认为这样做是可行的。 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')),
])
(当然,如果你沿着这条路走下去,你必须确保不要建立任何循环的父/子关系,否则你会回到原点:-))