【问题标题】:Wagtail: How to filter text in streamfield within model.pyWagtail:如何在 model.py 中过滤流域中的文本
【发布时间】:2018-01-24 08:25:24
【问题描述】:

我想编写一个过滤器来替换我的流域文本中的一些 $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')

【问题讨论】:

  • 能否将代码添加到您的 BasicStreamBlock 中?这会有所帮助。
  • @LBBenJohnston:完成,谢谢

标签: python django wagtail wagtail-streamfield


【解决方案1】:

这是一种在 CityPage 模型中简单地从流域生成模板化(转换后的)html 输出的方法。

概述:

  • 使用 Python 内置的basic Template system(或Python 3 docs),既简单又省去了直接处理替换的麻烦。
  • Python 的内置模板系统使用$variablename 而不是$variablename$,但效果很好,如果确实需要可以配置。
  • 避免尝试手动构建流场中的块,最好只使用 str(self.streamfield) 之类的东西,这将强制它呈现为漂亮的 HTML。
  • 请记住,您可以使用 class Meta: template = ... see docs 为任何流块自定义 html。
  • 一旦我们从流域获得了 HTML 输出,我们就可以使用 string.Template 类通过提供模板名称的字典以及替换它们的内容来创建我们的输出文本。模板变量名称应该在其中包含 $ 符号(variablename 不是 $variablename),库会为您处理这些,它还负责基本的字符串转换。李>
  • 为了简单起见,我使用了一个有用的来自 Django 的 model_to_dict 实用程序,将 CityObject 转换为直接传递给模板的字典(将其视为 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 %}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 2019-07-09
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多