【问题标题】:Django templates and whitespaceDjango 模板和空格
【发布时间】:2016-10-16 16:49:05
【问题描述】:

我开始在我的 django 模板中使用自定义 inclusion tags。例如,我有一个 {% profilelink profile %} 标记,它插入一个指向用户个人资料的链接以及个人资料图片的小版本,就像这样 (profilelink.html):

<a href='{% url ... %}'><img src='{{ ... }}' alt='...'> {{ profile.name }}</a>

但是,当我在下面的 sn-p (sometemplate.html) 中使用它时:

<p>Owned by {% profilelink owner %} (uploaded by {% profilelink uploader %})</p>

然后我在第二个模板标签和右括号生成的 HTML 之间得到了空格。这个空格是不需要的。它来自文件 profilelink.html 中的最后一个换行符。这是一个非常常见的问题,搜索 Stackoverflow 通常会产生很多关于模板中空白的问题。以下是迄今为止找到的解决方案的摘要以及它们不起作用的原因:

其中一些问题可以通过{% spaceless %} 标签解决,但不是全部。此标记仅删除 标记之间的空格,而上例中并非如此。

一种可能的解决方案是在 profilelink.html 中没有最终 EOL,但这是非常不可取的。原因:一般是风格不好;一些编辑器(vim)默认默认添加一个;这就是POSIX defines a line;这可能会让一些 SCM 不高兴;等等

另一个解决方案是切换到另一个模板引擎,比如Jinja2,它可能会也可能不会解决这个问题。它支持像 {% ... -%} 这样吃下一个 EOL 字符的结构。这在某些情况下很有用,但对于我上面的示例也无用。但是为了这样一个小麻烦而切换模板后端似乎有点矫枉过正,并增加了另一个依赖。我想坚持任何标准的“django”做事方式。不过,显然有计划让 Jinja2 成为新的 Django 默认设置。

有些人建议在生成的 HTML 发送到浏览器之前使用中间件类来删除多余的空格。这很有用,但仅用于以功能等效的方式转换 HTML,即相同的语义:它仍将在浏览器中以相同的方式显示。这不是我想要的,我想要语义上的实际变化以使其正确显示。这是不可能在通用中间件类中实现的。我需要在模板本身中根据具体情况对此进行控制。我不在乎让 HTML 更漂亮,我首先关心的是它是否正确。

还有bug #2594 已作为 WONTFIX 关闭,并带有参数(引用)“Django 模板语言足以生成对空格不敏感的 HTML”。在我看来,这是完全错误的。 HTML 对空白非常敏感,它只是不关心它有多少。它非常关心是否有一些空白或根本没有。

我的一些问题是:有什么理智的方法可以解决这个问题吗? (一个总是有效的,不仅仅是在某些情况下。)

(任何基于 CSS 的修复都不算在内。复制/粘贴意外是邪恶的。)

【问题讨论】:

  • 不是最优雅的解决方案,但您可以考虑使用 get_template 而不是 @register 装饰器,然后在注册标签之前从模板字符串中删除换行符。再想一想,也可以把它做成一个装饰器。
  • @Selcuk 我尝试这样做但没有成功。至少不是没有深入到模板系统的内部,这是我想避免的。如果您或其他人可以发布可行的解决方案,那就太好了。
  • 我没有检查,但如果您使用macrosjinja 应该可以解决您的问题。 Django 模板非常限制我的口味。您甚至可以将jinja 用于文本电子邮件,尽管它仍然是tricky。我想知道是否有一个模板引擎(不一定在 Python 中)对此有好处......

标签: python django django-templates


【解决方案1】:

我相信一种解决方案是使用simple_tag 而不是包含标签,希望不会造成太多混乱。

我假设你的标签是这样的:

@register.inclusion_tag('profilelink.html')
def profilelink(user):
    return {"profile": user}

这个可以换成

from django.template.loader import render_to_string

@register.simple_tag
def profilelink(user):
    t = render_to_string("profilelink.html", {"profile": user})
    return t.strip()

现在我面前没有 Django 项目,所以这是未经测试的。

【讨论】:

  • 不错的解决方案。对我来说,html 在呈现的模板中逐字显示。所以必须将最后一行更改为return format_html(t.strip()),如上所述here
【解决方案2】:

这是迄今为止我想出的最好的。我仍然希望有更好的解决方案,但现在可以了。

我在 base/templatetags/basetags.yp (taken from this answer) 中定义了这样的自定义过滤器:

from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def trim(value):
    return value.strip()

然后按如下方式使用:

{% load basetags %}
<p>Owned by {% profilelink owner %} (uploaded by
{% filter trim %}{% profilelink uploader %}{% endfilter %})</p>

【讨论】:

    猜你喜欢
    • 2010-10-17
    • 2014-09-24
    • 2012-01-02
    • 2010-12-26
    • 2013-01-22
    • 2014-06-17
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多