【问题标题】:Using StreamField contents programmatically from withing the Page get_context function在 Page get_context 函数中以编程方式使用 StreamField 内容
【发布时间】:2017-01-26 04:23:06
【问题描述】:

我一直在尝试学习 Wagtail,使用 StreamFields 和积木的复杂性让我头疼。按照 Wagtail 文档和演示应用程序,我没有遇到任何问题,但如果没有外部帮助,我似乎无法克服这些问题。

这是我正在尝试(但失败)实现的目标。

在使用 Blog 应用程序时,我尝试对其进行扩展,以便 StreamField 允许添加基于 pygments 的带有语法高亮显示的代码块。源代码由自定义的StructBlock 类(自然是CodeBlock)管理,并且是BlogPageStreamField 主体的一部分。在 Wagtail 管理员中,我可以输入代码、使用的语言、要应用的突出显示样式以及是否显示行号。这一切都很好,直到我想根据所选的突出显示样式为渲染模板选择附加样式表。以下是页面模板如何包含样式表:

{% 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 %}

CodeBlock 在渲染方法中完成了它的工作(这个想法很感激地发现 - 并且无耻地使用了 - 在线)。在应用程序流程的这一点上,将突出显示样式添加到页面上下文为时已晚,因此我尝试在覆盖的 def get_context 函数中分解页面正文字段,但没有成功。我只是无法通过 BlogPage 类中的任何类成员访问底层 JSON 文本或访问数据。

有没有办法在从数据库加载数据之后,在交给模板之前将突出显示样式添加到页面上下文中?

这是我的基本博客页面:

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 类:

class CodeBlock(StructBlock):
    LANGUAGE_CHOICES = (
        ('aspx-cs', '.NET ASP/C#'),
        ('aspx-vb', '.NET ASP/VisualBasic'),
        ('csharp', '.NET C#'),
        ('fsharp', '.NET F#'),
        ('vbnet', '.NET VisualBasic'),
        ('ng2', 'Angular 2'),
        ('html+ng2', 'Angular 2 Html'),
        ('apache', 'Apache Config'),
        ('arduino', 'Arduino Sketch'),
        ('asm', 'Assembly'),
        ('bash', 'Bash Shell'),
        ('batch', 'Batch CMD File'),
        ('c', 'C'),
        ('cpp', 'C++'),
        ('cmake', 'CMake'),
        ('coffeescript', 'Coffee Script'),
        ('css', 'CSS'),
        # ... and many, many more ...
        ('vhdl', 'Vhdl'),
        ('registry', 'Windows Registry'),
        ('xml', 'XML'),
        ('xml+php', 'XML/PHP'),
        ('xslt', 'XSLT'),
        ('yaml', 'Yaml'),
    )

    COLORIZER_CHOICES = (
        ('abap', 'Abap'),
        ('algol', 'Algol'),
        ('algol_nu', 'Algol Nu'),
        # ... finish the list with all the highlight styles in the current version of pygments
        ('vs', 'Vs'),
        ('xcode', 'Xcode'),
    )

    language = ChoiceBlock(choices=LANGUAGE_CHOICES, classname='full')
    colors = ChoiceBlock(choices=COLORIZER_CHOICES, classname='full')
    code = TextBlock()
    line_numbers = BooleanBlock(classname='full')

    class Meta:
        icon = 'code'

    def render(self, value, context=None):
        src = value['code'].strip('\n');
        lang = value['language']
        line_nos = value['line_numbers']

        lexer = get_lexer_by_name(lang)
        formatter = get_formatter_by_name('html', linenos='table' if line_nos else False, cssclass='codehilite', style='default',noclasses=False)
        return mark_safe(highlight(src, lexer, formatter))

【问题讨论】:

  • 请您详细说明您在get_context 方法中已经尝试并未能实现的目标?访问self.body 肯定会为您提供您感兴趣的数据。
  • 谢谢,我的错误是我忘记发布页面了,所以当我遍历 body 块时没有包含新块...

标签: python wagtail wagtail-streamfield


【解决方案1】:

几个小时的睡眠如何帮助您理清思维过程真是太神奇了!很抱歉浪费了您的时间。

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

正如gasman 在他的评论中建议的那样,在BlogPage 中覆盖get_context 可以让您直接访问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函数总是设置'default'着色器,如果用户没有选择一个,{% if code_colorizer %}检查和它的{% else %}分支可以完全删除。

对于想要使用此代码的任何人,请注意,在同一页面上使用不同语法突出显示样式的多个代码块将无法按预期工作。实际上,页面类仅包括最后一个代码块的选定样式表。如果在每个代码块中选择了所有不同的 CSS 文件,我可以添加所有不同的 CSS 文件,但是由于 pygments 荧光笔使用相同的 CSS 类名,因此 HTML 文件中的多个样式仍然无法按您的意愿工作。当然,可以使用 pygments API 为每个突出显示样式生成一个封闭的&lt;div&gt;&lt;/div&gt; 标记(在CodeBlockrender 函数中),然后编辑相应的CSS 文件以添加相同的类到每个元素,但这超出了这个问题的范围。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 2018-08-29
    • 1970-01-01
    • 2015-06-21
    相关资源
    最近更新 更多