在 StructBlock 中存储内容和预渲染内容

Storing both content and pre-rendered content in a StructBlock

为了避免每次查看页面时都呈现降价,我的页面模型中有两个 TextField。一个用于在管理站点中输入降价,第二个隐藏的 TextField,我在页面保存期间将呈现的 html 存储在其中。

现在,我正在尝试向 Markdown StructBlock 添加类似的功能,以便在 StreamField 中使用。目前,我在每个页面视图上呈现 html。 AIUI Blocks 的实例存储为(名称,值)元组。

是否 feasible/sensible 在存储的元组中添加第三个 'rendered' 元素并在某些新的派生块中添加覆盖方法 class?

或者这是否可以通过(部分)页面缓存更好地解决?

在数据库中,StructBlock 存储为字典,因此如果您的降价块基于 StructBlock,则向该字典添加一个额外的键最有意义。 (你部分正确,StreamBlock 中的项目通常表示为(名称,值)元组,但使用它需要深入挖掘 StreamBlock 与其子项之间的交互,我认为这会使这里的事情过于复杂。)

所有块实现一对方法get_prep_value(value)(在将块写入数据库时​​使用,并将块的本机Python值转换为JSON-可以存储在数据库中的可序列化版本)和 to_python(value)(在从数据库中检索它时再次将其转换回来)。考虑到这一点,这里有两个步骤要实施:

  • 覆盖 get_prep_value 以生成渲染版本并将其插入数据库表示
  • 覆盖 to_python 以确保在解包数据库表示时保留呈现的版本(这不会自动发生,因为 StructBlock 只会解包它知道的子块,而呈现的 HTML 值不是其中之一)

第二部分有一个额外的复杂性,因为 StructBlock 实现了一个 bulk_to_python(values) 方法作为性能优化 - 这会一次性解包值列表,以利用任何处理更多的子块以这种方式有效(例如需要数据库查找的那些),并绕过通常的 to_python 方法,因此您也需要覆盖该方法。

假设您的起点是这样的:

class MarkdownBlock(StructBlock):
    markdown_text = TextBlock()
    some_other_property = CharBlock()

你想要这样的东西:

class MarkdownBlock(StructBlock):
    markdown_text = TextBlock()
    some_other_property = CharBlock()

    def get_prep_value(self, value):
        value_to_save = super().get_prep_value(value)
        value_to_save['rendered_text'] = render_markdown(value_to_save['markdown_text'])
        return value_to_save

    def to_python(self, value):
        python_val = super().to_python(value)
        python_val['rendered_text'] = value['rendered_text']
        return python_val

    def bulk_to_python(self, values):
        python_values = super().bulk_to_python(values)
        for i, val in enumerate(python_values):
            val['rendered_text'] = values[i]['rendered_text']
        return python_values

然后在访问模板上的块值时,应该有望使 rendered_textmarkdown_textsome_other_property 一起可用。