在 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_text
与 markdown_text
和 some_other_property
一起可用。
为了避免每次查看页面时都呈现降价,我的页面模型中有两个 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_text
与 markdown_text
和 some_other_property
一起可用。