需要使用侧边栏导航创建一个长滚动页面以进行页面导航。这意味着每个标题都有一个id。我可以在流场级别验证以确保用户没有输入重复的ID吗?
编辑:
标题定义如下:
class HeadingOneBlock(blocks.StructBlock):
id = blocks.RegexBlock(regex=r'^\S*$', help_text='No spaces or special characters')
heading = blocks.CharBlock()
class Meta:
template = 'base/heading_one.html'
icon = 'title'
label = 'h1'
页面:
class LongScrollPage(Page):
banner_text = RichTextField()
description = RichTextField()
body = StreamField([
('heading1', HeadingOneBlock()),
('heading2', HeadingTwoBlock()),
('paragraph', blocks.RichTextBlock(features=['bold', 'italic', 'ol', 'ul', 'link', 'image', 'hr'])),
('collapsible_panel', CollapsiblePanelBlock()),
('table', TableBlock(template='base/tables.html')),
], blank=True, null=True)
content_panels = Page.content_panels + [
FieldPanel('banner_text'),
FieldPanel('description'),
StreamFieldPanel('body'),
]
有没有办法在“身体”级别进行验证?我知道我可以在块级别进行验证,但是如何确保ID是唯一的?
答案 0 :(得分:1)
根据wagtail的作者,您显然not supposed to access stream_data directly就是这种方式,但是可以稍微修改上面的代码以获得相同的效果。
def validate_ids_in_headings(value):
# value.stream_data is a list of tuples
# first item in each tuple is the label (eg. 'heading1' or 'paragraph')
# second item in each tuple is a StructValue which is like an ordered dict
items = [
data.value.get('id')
for data in value
]
if len(set(items)) != len(items):
# sets can only be unique so - the items are are not unique
# must raise special StreamBlockValidationError error like this
raise StreamBlockValidationError(
non_block_errors=ValidationError(
'All headings must have unique ID values: %(value)s',
code='invalid',
params={'value': items},
)
)
# if valid, do nothing
我认为这应该照顾您的情况,并且它不依赖于不应直接访问的字段。
答案 1 :(得分:0)
解决此问题的一种方法是使用validators
上的自定义StreamField
属性。
您可以阅读有关Django Form Validation的更多信息。
此外,提供给验证程序的value
是[StreamValue](https://github.com/wagtail/wagtail/blob/master/wagtail/core/blocks/stream_block.py#L324)
的实例,其具有属性stream_data
,其中包含元组列表。每个元组中的第一项是您给出块的标签(例如,示例中的heading1,heading2,段落)。第二项是StructValue
实例,其中每个子块值可以通过其键hence data[1].get('id')
在下面的示例中访问。
验证码(也可以在models.py文件中):
from django.core.exceptions import ValidationError
from wagtail.core.blocks import StreamBlockValidationError # plus all blocks imported here
def validate_ids_in_headings(value):
# value.stream_data is a list of tuples
# first item in each tuple is the label (eg. 'heading1' or 'paragraph')
# second item in each tuple is a StructValue which is like an ordered dict
items = [
data[1].get('id')
for data in value.stream_data
if 'heading' in data[0]
]
if len(set(items)) != len(items):
# sets can only be unique so - the items are are not unique
# must raise special StreamBlockValidationError error like this
raise StreamBlockValidationError(
non_block_errors=ValidationError(
'All headings must have unique ID values: %(value)s',
code='invalid',
params={'value': items},
)
)
# if valid, do nothing
修订的型号代码:
# using one HeadingBlock class here as you can define template/label within the StreamField
class HeadingBlock(StructBlock):
id = RegexBlock(regex=r'^\S*$', help_text='No spaces or special characters')
heading = CharBlock()
class Meta:
icon = 'title'
body = StreamField([
('heading1', HeadingBlock(label='h1', template='base/heading_one.html')), # note: label/template set here
('heading2', HeadingBlock(label='h2', template='base/heading_two.html')), # note: label/template set here
('paragraph', RichTextBlock(features=['bold', 'italic', 'ol', 'ul', 'link', 'image', 'hr'])),
('collapsible_panel', CollapsiblePanelBlock()),
('table', TableBlock(template='base/tables.html')),
# validators set here, must be within a list - even if one item, removed null=True as not needed
], blank=True, validators=[validate_ids_in_headings])
这将向用户显示错误。
不幸的是,这不会突出显示标签(带有错误指示符),但它会在“正文”块的开头显示错误,并显示特定错误文本Issue 4122。
我在使用Python 3的BakeryDemo,Wagtail 1.13上测试了这个。
答案 2 :(得分:0)
对于 wagtail 2.11.8 版,这对我有用。 (这是对之前答案的修改)
"""Streamfield uniqueness validator"""
def streamfield_uniqueness_validator(value):
# value.stream_data is a list of tuples
# first item in each tuple is the label (eg. 'recipient_email')
# second item in each tuple is the actual value of field
# third item in each tuple is the id of tuple or dict
items = [
data[1].lower()
for data in value.stream_data
]
print(items)
if len(set(items)) != len(items):
# sets can only be unique so - the items are are not unique
# must raise special StreamBlockValidationError error like this
raise StreamBlockValidationError(
non_block_errors=ValidationError(
'Cannot add same email on multiple fields: %(value)s',
code='invalid',
params={'value': items},
)
)
在我的模型中:
class ModelName(models.Model):
stream_fileds = StreamField([('stream_filed', blocks.CharBlock())], validators=[streamfield_uniqueness_validator])