Python 如何在wagtail cms字段中包含上下文变量?

Python 如何在wagtail cms字段中包含上下文变量?,python,django,django-templates,wagtail,Python,Django,Django Templates,Wagtail,我正在寻找一种方法来呈现一个变量,该变量将在cms页面呈现的页面上下文中可用 例: 我有在上下文中登录的用户,我也有他在网站上做的最后一笔交易 我希望Wagtail中的富文本字段中的文本是这样的,以便营销团队可以调整副本 你好| |名字| |谢谢您的购买||产品名称| |将 很快就送到你这里。预计交付日期为 ||预期交货日期|| 为了减少混淆,我将双括号替换为双管道,以表明模板系统不需要为那些模板的django模板。使用简单的模板就足够了 我认为我可以通过以下方式实现这一目标: 一个流字段,其中

我正在寻找一种方法来呈现一个变量,该变量将在cms页面呈现的页面上下文中可用

例: 我有在上下文中登录的用户,我也有他在网站上做的最后一笔交易

我希望Wagtail中的富文本字段中的文本是这样的,以便营销团队可以调整副本

你好| |名字| |谢谢您的购买||产品名称| |将 很快就送到你这里。预计交付日期为 ||预期交货日期||

为了减少混淆,我将双括号替换为双管道,以表明模板系统不需要为那些模板的django模板。使用简单的模板就足够了 我认为我可以通过以下方式实现这一目标:

  • 一个流字段,其中包含富文本字段块和一个自定义块,其中包含可以使用的上下文变量
  • 一个自定义呈现函数,它将正则表达式并用上下文值替换富文本块中的合并标记
  • 为简单模板创建一个新过滤器。例如:{page.body | richtext | simpletemplate}

  • 是否有更明显的方法或开箱即用的方法从富文本字段中进行模板制作?

    如果每个插入的上下文变量都有一个单独的streamfield块,则会很麻烦。您必须覆盖将元素包装在
    div
    标记中的默认呈现。然而,我喜欢这对编辑来说更简单

    我以前做过一些类似于自定义渲染的事情,但是使用简单的文本字段来格式化特价代码消息。为Wagtail编辑器提供了以下
    帮助\u文本
    ,以说明:

    valid_placeholders = ['offer_code', 'month_price']
    template_text = models.TextField(
        _('text'),
        help_text="Valid placeholder values are: {all_valid}. Write as {{{example}}}".format(
            all_valid=", ".join(valid_placeholders),
            example=valid_placeholders[0],
        )
    )
    
    此呈现为有效占位符值的值为:报价\代码、月份\价格。写为{{offer_code}}

    然后在视图中:

    template_keys = [i[1] for i in Formatter().parse(template_text)]
    
    …并从那里继续渲染。记住也要使用上面的
    Formatter().parse()
    函数适当地验证字段

    我使用Django的模板格式,而不是Python的string.format(),因为它会以静默方式失败,但如果清理得当,可以使用string.format()


    自定义模板过滤器对我来说是最简单的,所以我会从这种方法开始,如果遇到困难,就切换到自定义渲染功能。

    我找到了一种更简单的方法。我希望我的编辑器能够为单个用户创建具有动态定制的页面。有了它,我的编辑器实际上能够将模板变量作为{{var}}放入任何类型的内容块中,其工作原理与Django模板语言类似。对于我的用例,我允许我的编辑在CMS中创建电子邮件内容,然后将其拉出来发送电子邮件:

    这是要调用的函数:

    def re_render_html_template(email_body, context):
        """
        This function takes already rendered HTML anbd re-renders it as a template
         this is necessary because variables added via the CMS are not caught by the
         first rendering because the first rendering is rendering the containing block,
         so instead they are rendered as plaintext in content the first render, e.g., {{ var }}
    
        Example:
        input: <p>Hey {{ user_account.first_name }}, welcome!</p>
        output: <p>Hey Brett, welcome!</p>
    
        @param email_body: html string
        @type email_body: str
        @param context: context dictionary
        @type context: dict
        @return: html string
        @rtype: str
        """
        from django.template import Context
        from django.template import Template
    
        template = Template(email_body)
        context = Context(context)
        email_body = template.render(context)
        return email_body
    

    自定义过滤器非常容易使用
    email_body = render_to_string(template, context)
    # need to re-render to substitute tags added via CMS
    email_body = re_render_html_template(email_body, context)