【问题标题】:Proper indentation in Django templates (without monkey-patching)?Django模板中的正确缩进(没有猴子补丁)?
【发布时间】:2013-08-20 22:40:00
【问题描述】:

我想为我的独立应用程序生成由 Django 模板系统预处理的人类可读的 HTML 和 CSS 代码(适当缩进)。

我已经修改了 django.template.base 模块中 NodeList 类的渲染方法。我的代码似乎工作正常,但我正在使用猴子补丁来替换旧的渲染方法。

在这种情况下,有没有更优雅的方法不使用猴子补丁?或者也许猴子补丁是这里最好的方法?

我的代码如下所示:

'''
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

【问题讨论】:

  • 我是 django 的新手,你能提供一个例子来说明我如何在我的项目中实现它吗?

标签: django django-templates indentation monkeypatching


【解决方案1】:

修改模板层是可以的,但不是最佳的,因为它只是处理节点的呈现方式,而不是整个文档。我会为您的项目推荐 writing custom middleware 以漂亮地打印 html 和 css 页面的呈现响应。

您的中间件需要实现process_template_response,它应该用于查看和更新​​SimpleTemplateResponse 对象:

  • 检查is_rendered 属性以查看响应是否已呈现
  • 通过以下任一方式验证文档类型:
    • template_name 属性的末尾查找所需的文件类型(.html.css
    • 查看 content_type 属性 (Django 1.5) 或可能 mimetype 用于较旧的安装
  • 重新格式化并更新您呈现的文档,使其看起来更漂亮(Beautiful Soup 非常适合 HTML,但您需要选择自己喜欢的漂亮打印机或自己动手制作)。

我认为中间件是一个更优雅的解决方案,因为它最终不会对您的文件进行词法更改。它与确定模板内容的逻辑完全分离(没有业务存在的地方)。最后,您希望您的所有 html 和 css 看起来都很棒,那么为什么首先将其与您的模板联系起来呢?

【讨论】:

    【解决方案2】:

    您可以使用类继承来创建不同的NodeList,但它可能需要在不同的一端进行一些修补。您的解决方案看起来简单明了。

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

    【讨论】:

      猜你喜欢
      • 2011-10-06
      • 2010-11-26
      • 1970-01-01
      • 1970-01-01
      • 2016-09-01
      • 2012-09-16
      • 2012-12-18
      • 2020-01-09
      • 1970-01-01
      相关资源
      最近更新 更多