使用Page get_context函数以编程方式使用StreamField内容

时间:2017-01-26 04:23:07

标签: python wagtail wagtail-streamfield

我一直在努力学习Wagtail,使用StreamField和块的错综复杂让我头疼。在Wagtail文档和演示应用程序之后我没有遇到任何问题,但如果没有外部帮助,那么超出这个范围似乎是不可克服的。

这是我正在尝试(并且失败)的目标。

在使用博客应用程序时,我尝试对其进行扩展,以便StreamField允许添加基于 pygments 的语法突出显示的代码块。源代码由自定义StructBlock类(CodeBlock自然地)管理,并且是StreamField的{​​{1}}正文的一部分。在Wagtail管理员中,我可以输入代码,使用的语言,要应用的突出显示样式以及是否显示行号。这一切都非常好,直到我想根据所选的高光样式为渲染模板选择其他样式表。以下是页面模板将包含样式表的方式:

BlogPage

{% block extra_css %} {# This goes in the page <head> section #} {% if has_code_block %} {% if code_colorizer %} <link rel="stylesheet" type="text/css" href="{% static 'css/highlight_{{ code_colorizer }}.css' %}"> {% else %} <link rel="stylesheet" type="text/css" href="{% static 'css/highlight_default.css' %}"> {% endif %} {% endif %} {% endblock %} 在渲染方法中完成了它的工作(感激地发现了 - 并且无耻地使用 - 在线)。在app流程的这一点上,将高亮样式添加到页面上下文为时已晚,所以我尝试在覆盖的def get_context函数中分解页面主体字段,但没有成功。我只是无法通过CodeBlock类通过任何类成员访问基础JSON文本或访问数据。

有没有办法在从数据库加载数据之后,在将数据加载到模板之前,将高亮样式添加到页面上下文中?

这是我的基本博客页面:

BlogPage

这是我的class BlogPage(Page): tags = ClusterTaggableManager(through=BlogPageTag, blank=True) posted_date = models.DateField("Post date") edited_date = models.DateField("Edited date", null=True, blank=True) feed_image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') body = StreamField(BlogStreamBlock) search_fields = Page.search_fields + [ index.SearchField('body') ] subpage_types = [] parent_page_types = ['BlogIndexPage'] @property def blog_index(self): return self.get_ancestors().type(BlogIndexPage).last() BlogPage.content_panels = [ FieldPanel('title', classname='full title'), FieldPanel('posted_date'), FieldPanel('edited_date'), StreamFieldPanel('body'), InlinePanel('related_links', label="Related links"), ] BlogPage.promote_panels = Page.promote_panels + [ ImageChooserPanel('feed_image'), FieldPanel('tags'), ] 类的定义:

BlogStreamBlock

最后,这是class BlogStreamBlock(StreamBlock): subtitle = CharBlock(icon='title', classname='title') abstract = RichTextBlock(icon='pilcrow') paragraph = RichTextBlock() aligned_image = ImageBlock() source_code = CodeBlock() quote = QuoteBlock() 类:

CodeBlock

1 个答案:

答案 0 :(得分:0)

令人惊讶的是,几个小时的睡眠有助于澄清您的思维过程!抱歉浪费了你的时间。

仅在管理编辑器中保存页面是不够的!你也必须发布它!

正如加油员在他的评论中所建议的那样,在get_context中覆盖BlogPage可让您直接访问body班级成员。在那里,我可以遍历元素,检查他们的block_type并访问他们的子元素,如下所示:

def get_context(self, request, *args, **kwargs):
    context = super(BlogPage, self).get_context(request)
    if self.body and len(self.body) > 0:
        for block in self.body:
            if block.block_type == 'source_code':
                context['has_code_block'] = True
                context['code_colorizer'] = block.value['colors'] if block.value['colors'] else 'default'
    return context

这将确保当页面上有一个源代码块时,CSS样式表始终可用。

现在让我们解决上面代码中的另一个明显错误。用于设置样式表的模板代码无法发布。它产生的是一些URL转义文本,如:

<link rel="stylesheet" type="text/css" href="/static/css/highlight_%7B%7B%20code_colorizer%20%7D%7D.css">

实际需要的是以下内容:

{% block extra_css %}
    {% if has_code_block %}
        {% if code_colorizer %}
            {% with 'css/highlight_'|add:code_colorizer|add:'.css' as colorizer_choice %}
                <link rel="stylesheet" type="text/css" href="{% static colorizer_choice %}">
            {% endwith %}
        {% else %}
            <link rel="stylesheet" type="text/css" href="{% static 'css/highlight_default.css' %}">
        {% endif %}
    {% endif %}
{% endblock %}

实际上,由于get_context函数始终设置'默认'着色器,如果用户未选择一个,则{% if code_colorizer %}检查及其{% else %}分支可以完全删除。< / p>

对于想要使用此代码的任何人,请注意使用不同的语法突出显示样式在同一页面上具有多个代码块将无法按预期工作。实际上,页面类仅包括最后一个代码块的选定样式表。我可以添加所有不同的CSS文件,如果已经在每个代码块中选择了它,但由于pygments highlighter使用相同的CSS类名,因此在HTML文件中有多个样式仍然无法按照您的要求工作。当然,可以使用pygments API生成一个封闭的<div></div>标记,其中包含每个突出显示样式的特定类(在render的{​​{1}}函数中),然后编辑相应的CSS将这个相同的类添加到每个元素的文件,但这超出了这个问题的范围。