我想编写一个过滤器来替换流域文本中的一些$ variables $。在我的“页面”模型中执行此操作的最佳方法是什么?我尝试了以下操作,但如果我将模型保存为草稿并在之后发布,则有时无效。有没有人知道更好的方法呢?
class CityPage(Page, CityVariables):
cityobject = models.ForeignKey(CityTranslated, on_delete=models.SET_NULL, null=True, blank=True)
streamfield = StreamField(BasicStreamBlock, null=True, blank=True)
content_panels = Page.content_panels + [
FieldPanel('cityobject', classname="full"),
StreamFieldPanel('streamfield'),
]
def get_streamfield(self):
for block in self.streamfield:
if type(block.value) == unicode:
block.value = self.replace_veriables(block.value)
elif type(block.value) == RichText:
block.value.source = self.replace_veriables(block.value.source)
else:
print "notimplemented"
return self.streamfield
这只是用我的数据库中的值替换$ variables $的类。
class CityVariables():
def replace_veriables(self, repstr):
reprules = self.get_city_context()
for key, value in reprules.iteritems():
repstr = repstr.replace(key, value)
return repstr
def get_city_context(self):
context = {}
if self.cityobject.population:
context['$population$'] = unicode(self.cityobject.population)
if self.cityobject.transregion:
context['$region$'] = unicode(self.cityobject.transregion)
return context
class BasicStreamBlock(blocks.StreamBlock):
h2 = blocks.CharBlock(icon="title", classname="title")
h3 = blocks.CharBlock(icon="title", classname="title")
h4 = blocks.CharBlock(icon="title", classname="title")
h5 = blocks.CharBlock(icon="title", classname="title")
paragraph = blocks.RichTextBlock(icon="pilcrow")
image = ImageChooserBlock(label="Image", icon="image")
aligned_html = blocks.RawHTMLBlock(icon="code", label='Raw HTML')
答案 0 :(得分:1)
这是一种从CityPage模型中简单地从streamfield生成模板化(转换)html输出的方法。
<强>概述:强>
$variablename
而非$variablename$
,但效果很好,可以在真正需要时进行配置。str(self.streamfield)
这样会强制它渲染成漂亮的HTML。class Meta: template = ...
see docs自定义任何streamblock的html。string.Template
类来创建输出文本,方法是提供模板名称的字典以及替换它们的内容。模板变量名称不其中包含$
符号(variablename
而非$variablename
),库会为您处理,它也会照顾基本字符串转换。model_to_dict
util来使CityObject
成为一个直接传递给模板的dict(想想这是Django模板的上下文)。 $region
无效,需要匹配字段名称,例如。 $transregion
- 或者只是更改字段名称。如果所有变量/字段名都匹配,它可以让以后更容易阅读代码。city_page.html
模板中使用此输出之前,我们需要将其标记为Django直接呈现的安全。 重要提示:请注意这一点,因为这意味着有人可以将javascript代码保存到CityObject中并在前端运行,您可能需要model_to_dict
之后的其他图层来清除任何潜在的js代码。示例:myapp / models.py
from django.forms.models import model_to_dict
from django.utils.safestring import mark_safe
from string import Template
# other imports... Page, etc
class CityPage(Page):
cityobject = models.ForeignKey(
CityTranslated, on_delete=models.SET_NULL, null=True, blank=True)
streamfield = StreamField(BasicStreamBlock, null=True, blank=True)
content_panels = Page.content_panels + [
FieldPanel('cityobject', classname="full"),
StreamFieldPanel('streamfield'),
]
def get_templated_streamfield(self):
# using str is a quick way to force the content to be rendered
rendered_streamfield = str(self.streamfield)
# will generate a dict eg. {'population': 23000, 'transregion': 'EU'}
# will not convert to values string/unicode - but this is handled by Template
template_variables = model_to_dict(self.cityobject)
template = Template(rendered_streamfield)
# using safe_substitute will **not** throw an error if a variable exists without a value
converted = template.safe_substitute(template_variables)
# as we have html markup we must mark it as safe
return mark_safe(converted)
示例:myapp / template / city_page.html
{% extends "base.html" %}
{% load wagtailimages_tags %}
{% block content %}
{% include "base/include/header.html" %}
<div class="container">
<div class="row">
<div class="col-md-6">
<em>Streamfield Original (without templating)</em>
{{ page.streamfield }}
</div>
<div class="col-md-2">
<em>Streamfield with templating</em>
{{ page.get_templated_streamfield }}
</div>
</div>
</div>
{% endblock content %}