4

スタンドアロン アプリケーション用に、Django テンプレート システムによって前処理された、人間が判読できる HTML および CSS コード (適切にインデントされたもの) を生成したいと考えています。

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
4

2 に答える 2

3

テンプレート レイヤーの変更は問題ありませんが、ドキュメント全体ではなくノードのレンダリング方法を処理するだけなので、最適ではありません。プロジェクト用のカスタム ミドルウェアを作成して、html および css ページのレンダリングされた応答をきれいに印刷することをお勧めします。

オブジェクトprocess_template_responseの表示と更新に使用するミドルウェアを実装する必要があります。SimpleTemplateResponse

  • 属性をチェックしてis_rendered、応答がレンダリングされたかどうかを確認します
  • 次のいずれかでドキュメント タイプを確認します。
    • 属性の末尾にある目的のファイル タイプ ( .html、 ) を探します.csstemplate_name
    • 属性 ( Django content_type1.5) またはmimetype古いインストールを調べる
  • レンダリングされたドキュメントを再フォーマットして更新し、見栄えを良くします ( HTML にはBeautiful Soupが最適ですが、好みのプリティ プリンターを選択するか、独自のプリンターを作成する必要があります)。

ミドルウェアは最終的にファイルに語彙的な変更を加えないため、はるかに洗練されたソリューションだと思います。テンプレートのコンテンツを決定するロジックから完全に分離されています (ビジネスの対象とならない場合)。最後に、すべての html と css の見栄えを良くしたいのに、そもそもそれをテンプレートに結びつける必要はありません。

于 2013-08-29T17:49:44.997 に答える
1

クラスの継承を使用して別のものを作成できますNodeListが、おそらく別の端にパッチを適用する必要があります。あなたの解決策は単純明快に思えます。

class MyNodeList(NodeList):
    def render(self, context):
        # call super if you require so
        # your reindent functionality
于 2013-08-19T07:49:38.470 に答える