有没有比这更好的方法来创建具有固定内容的ListBlock
的子类?
class MixedMediaCarouselBlock(blocks.ListBlock):
"""
A hghly streamlined CarouselBlock which displays only Images and/or Videos.
"""
def __init__(self, child_block=None, **kwargs):
child_block = blocks.StructBlock([
('image', ImageChooserBlock(required=False)),
('video', EmbedBlock(
label="Video URL",
help_text="Paste the video URL from YouTube or Vimeo."
" e.g. https://www.youtube.com/watch?v=l3Pz_xQZVDg"
" or https://vimeo.com/207076450.",
required=False
)
),
])
super(MixedMediaCarouselBlock, self).__init__(child_block, **kwargs)
class Meta:
template = 'core/blocks/mixed_media_carousel_block.html'
label = 'Mixed Media Carousel'
icon = 'media'
以这种方式做到这一点真的很麻烦,但我找不到任何其他明显的方法,因为ListBlock
要求child_block
构造函数的参数,而其他块类型不
我想要一个ListBlock
子类的原因是在我的一个页面的StreamField
中将它用作单个块类型:
class News(Page)
assets = StreamField(
MixedMediaCarouselBlock(),
help_text='Pick one or more images/videos to place in the sidebar of this article.'
)
也许我只是做错了?
编辑:是的,我确实做错了什么。这根本不起作用,正如我刚刚发现的那样,当我尝试使用此设置保存页面并在wagtail / wagtailcore / blocks / stream_block.py第401行上获得AttributeError: 'MixedMediaCarouselBlock' object has no attribute 'child_blocks'
时。(Wagtail 1.12.2) 。不过不知道为什么。
EDIT2:我听了@ gasman的建议,想出了这个:
class MixedMediaCarouselBlock(blocks.StreamBlock):
slides = blocks.ListBlock(
blocks.StructBlock([
('image', ImageChooserBlock(required=False)),
('video', EmbedBlock(
label="Video URL",
help_text="Paste the video URL from YouTube or Vimeo."
" e.g. https://www.youtube.com/watch?v=l3Pz_xQZVDg or https://vimeo.com/207076450.",
required=False
)
),
])
)
但我仍然在页面编辑表单上获得了一个块类型菜单(我使用wigtail-facelift):
更糟糕的是,该表单允许我向StreamField添加多个slides
实例,这很容易导致用户意外地生成多个单元素ListBlocks,而不是一个多元素ListBlock,这会破坏渲染器。我该怎么办?
class MixedMediaCarouselBlock(blocks.StructBlock):
"""
A hghly streamlined CarouselBlock which displays only Images and/or Videos.
"""
slides = blocks.ListBlock(
blocks.StructBlock([
('image', ImageChooserBlock(required=False)),
('video', EmbedBlock(
label="Video URL",
help_text="Paste the video URL from YouTube or Vimeo."
" e.g. https://www.youtube.com/watch?v=l3Pz_xQZVDg or https://vimeo.com/207076450.",
required=False
)
),
])
)
class Meta:
template = 'core/blocks/mixed_media_carousel_block.html'
label = 'Mixed Media Carousel'
icon = 'media'
class News(Page):
...
assets = StreamField(
('media', MixedMediaCarouselBlock()),
help_text='Pick one or more images/videos to place in the sidebar of this article.'
)
然后,为了解决用户在一个MixedMediaCarouselBlock
内意外添加多个MixedMediaCarouselBlock
而不是多个视频/图片的问题,我破解了一些LESS CSS来隐藏可以让他们做的UI的是:
body.model-news {
.stream-menu .toggle {
display: none;
}
.sequence-controls:not(.list-controls) button[id$=delete] {
display: none;
}
}
在我的R& D期间,我遇到了Wagtail 1.12补丁说明,其中提到min_num
,max_num
和block_counts
meta attrs添加到StreamBlock
,听起来很有希望。但它们不会影响用户界面;他们只是添加了服务器端验证,使得无效选择在POST后显示为表单错误。如果他们首先阻止了无效的更改,我实际上可以使用它们。
答案 0 :(得分:2)
据我所知,您的块定义是正确的。 ListBlock不是设计为子类的,所以尝试这样做不可避免地会有点hacky并且不能保证在Wagtail发行版中保持稳定 - 但是你不依赖于ListBlock的任何内部,只是改变构造函数的方法签名,所以它应该足够安全。请记住,如果您继承StructBlock,StreamBlock或ChoiceBlock以外的任何块,则对您的子类的引用将出现在迁移文件中,因此,只要存在这些迁移,您就有责任保持类定义:请参阅{{ 3}}
这里的问题是StreamBlock(和子类)是目前唯一允许作为StreamField的顶级块的块类型:允许其他块类型(http://docs.wagtail.io/en/v1.12.2/topics/streamfield.html#streamfield-definitions-within-migrations)但尚未实现然而。作为解决方法,您可以将MixedMediaCarouselBlock定义为仅具有一个子块类型的StreamBlock;这并不像听起来那么笨重,因为在这种情况下会跳过选择块类型的菜单(#2048),这会使行为与ListBlock大致相同。