2017-01-26 14 views
0

我一直在試圖學習W and和使用StreamField s和塊的複雜性讓我頭疼。遵循W doc文檔和演示應用程序,我沒有任何問題,但是如果沒有外部幫助,超出這一點似乎是無法克服的。以編程方式使用StreamField內容使用頁面get_context函數

這是我正在嘗試(和失敗)實現。

當玩弄博客應用程序時,我試圖擴展它,以便StreamField允許基於基於語法高亮添加代碼塊。源代碼由自定義的StructBlock類(CodeBlock,自然地)管理,並且是BlogPageStreamField正文的一部分。在W admin管理員中,我可以輸入代碼,使用的語言,應用的高亮樣式以及是否顯示行號。這一切都很好,直到我想根據選定的突出顯示樣式爲渲染模板選擇其他樣式表。這裏是頁面模板如何包括樣式表:

{% 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)) 
+0

請您可以提供更多關於''get_context'方法中已經嘗試過但未能實現的細節?訪問'self.body'應該肯定會給你你感興趣的數據。 – gasman

+0

謝謝,我的錯誤是我忘了發佈頁面,所以當我在身體塊上打圈時,新塊不包括在內。 –

回答

0

這幾個小時的睡眠有助於澄清你的思維過程,這是驚人的!抱歉浪費你的時間。

僅將您的網頁保存在管理編輯器中是不夠的!你也必須發佈它!

正如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樣式表始終可用於當有頁面源代碼塊。

現在讓我們來解決上面代碼中的另一個明顯的錯誤。用於設置樣式表的模板代碼不能像發佈一樣工作。它所產生的一些網址轉義文本,如:

<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功能始終「默認」 colorizer,如果用戶不選擇一個,{% if code_colorizer %}支票和其{% else %}分支可以完全刪除。

對於任何想要使用此代碼的人,請注意,使用不同語法突出顯示樣式的同一頁上有多個代碼塊將無法按預期工作。實際上,頁面類僅包含最後一個代碼塊的選定樣式表。我可以添加所有不同的CSS文件,如果已經在每個代碼塊中選擇了這些文件,但由於pygments熒光筆使用相同的CSS類名稱,HTML文件中有多個樣式仍然不能按照您的要求工作。當然,可以使用pygments API爲每個突出顯示樣式生成一個包含<div></div>的標記(在CodeBlockrender函數中),然後編輯相應的CSS文件以將相同的類添加到每個元素,但是此超出了這個問題的範圍。

相關問題