2013-08-19 92 views
5

我想爲我的獨立應用程序生成由Django模板系統預處理的人類可讀的HTML和CSS代碼(正確縮進)。Django模板中的正確縮進(沒有猴子修補)?

我修改了從django.template.base模塊中找到的NodeList類的render方法。我的代碼似乎正常工作,但我使用猴子補丁來替換舊的渲染方法。

有沒有更優雅的方式,在這種情況下不使用猴子補丁?或者,也許猴子補丁是這裏最好的方式?

我的代碼如下所示:

''' 
This module monkey-patches Django template system to preserve 
indentation when rendering templates. 
''' 

import re 

from django.utils.encoding import force_text 
from django.utils.safestring import mark_safe 
from django.template.loader import render_to_string 
from django.template import Node, NodeList, TextNode 
from django.template.loader_tags import (BlockNode, ConstantIncludeNode, 
             IncludeNode) 


NEWLINES = re.compile(r'(\r\n|\r|\n)') 
INDENT = re.compile(r'(?:\r\n|\r|\n)([\ \t]+)') 


def get_indent(text, i=0): 
    ''' 
    Depending on value of `i`, returns first or last indent 
    (or any other if `i` is something other than 0 or -1) 
    found in `text`. Indent is any sequence of tabs or spaces 
    preceded by a newline. 
    ''' 
    try: 
     return INDENT.findall(text)[i] 
    except IndexError: 
     pass 


def reindent(self, context): 
    bits = '' 
    for node in self: 
     if isinstance(node, Node): 
      bit = self.render_node(node, context) 
     else: 
      bit = node 
     text = force_text(bit) 

     # Remove one indentation level 
     if isinstance(node, BlockNode): 
      if INDENT.match(text): 
       indent = get_indent(text) 
       text = re.sub(r'(\r\n|\r|\n)' + indent, r'\1', text) 

     # Add one indentation level 
     if isinstance(node, (BlockNode, ConstantIncludeNode, IncludeNode)): 
      text = text.strip() 
      if '\r' in text or '\n' in text: 
       indent = get_indent(bits, -1) 
       if indent: 
        text = NEWLINES.sub(r'\1' + indent, text) 

     bits += text 

    return mark_safe(bits) 


# Monkey-patching Django class 
NodeList.render = reindent 
+0

我對django相當新,你能提供一個我如何在我的項目中實現這個功能的例子嗎? –

回答

1

你可以使用類繼承來創建一個不同的NodeList但它可能會需要在不同的結束一些修補。你的解決方案看起來簡單明瞭。

class MyNodeList(NodeList): 
    def render(self, context): 
     # call super if you require so 
     # your reindent functionality 
3

修改模板層可以,但不是最優的,因爲它只處理節點的渲染方式,而不是整個文檔。我會爲您的項目推薦writing custom middleware以漂亮地打印html和css頁面的呈現響應。

中間件需要實現process_template_response應該被用來查看和更新​​SimpleTemplateResponse對象:

  • 檢查is_rendered屬性,看看是否響應已經呈現
  • 通過任何驗證文檔類型:
    • 尋找在template_name屬性的端部的期望的文件類型(.html.css
    • (Django的1.5)或爲老年人安裝
  • 重新格式化並更新您呈現的文檔,以華麗的外觀(Beautiful Soup是偉大的HTML,但你需要選擇您的參訪可能mimetype縱觀content_type屬性漂亮的打印機或滾動你自己的)。

我認爲中間件是一個更優雅的解決方案,因爲這最終不會對您的文件進行詞彙更改。它與決定你的模板內容的邏輯完全分開(它沒有業務存在)。最後,你希望所有的html和css看起來都很棒,那麼爲什麼要把它和你的模板綁在一起呢?