Шаблоны Django и пробелы

я начал использовать custom включение теги в моих шаблонах django. Например у меня есть {% profilelink profile %} тег, который вставляет ссылку на профиль пользователя вместе с небольшой версией изображения профиля, например (profilelink.HTML-код):

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

однако, когда я использую его в следующем фрагменте (sometemplate.HTML-код):

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

затем я получаю пробелы между HTML, созданными вторым тегом шаблона и закрывающая круглая скобка. этот пробел нежелателен. Он исходит из последнего символа новой строки в файле profilelink.HTML-код. Это очень распространенная проблема, и поиск Stackoverflow дает много вопросов о пробелах в шаблонах в целом. Вот резюме решений, найденных до сих пор, и почему они не работают:

некоторые из этих проблем решаемы с {% spaceless %} - тег, но не все из них. Этот тег удаляет только пробелы между теги, чего нет в приведенном выше примере.

одним из возможных решений является отсутствие окончательного EOL в profilelink.HTML-код но это крайне нежелательно. Причины: это, как правило, плохой стиль; некоторые редакторы (vim) молча добавляют его по умолчанию; вот как POSIX определяет строку; он может сделать некоторые СДМ несчастным; и т. д.

другое решение переключается на другой движок шаблонов, например Jinja2, что может решить или не решить эту проблему. Он поддерживает такие конструкции, как {% ... -%} которые едят следующий символ EOL. Это полезно в некоторых ситуациях, но также бесполезно для моего примера выше. Но переключение бэкэнда шаблонов для такого небольшого раздражения кажется немного излишним и добавляет еще одну зависимость. Я хотел бы придерживаться того, что является стандартным способом "Джанго". Однако, по-видимому, есть планы сделать Jinja2 новым дефолтом Django.

некоторые люди рекомендуется использовать класс промежуточного программного обеспечения для удаления избыточных пробелов из сгенерированного HTML перед его отправкой в браузер. Это полезно, но только для преобразования HTML функционально эквивалентным образом, т. е. той же семантики: он будет отображаться таким же образом в браузере. Это не то, что я хочу, я хочу фактическое изменение семантики, чтобы она отображалась правильно. Это невозможно реализовать в универсальном промежуточном классе. Мне нужен контроль. это на индивидуальной основе самого шаблона. Я не забочусь о том, чтобы сделать HTML красивее, я забочусь о том, чтобы он был правильным в первую очередь.

там же ошибка #2594 который был закрыт как WONTFIX с аргументом (цитата) "язык шаблонов Django достаточно хорош для генерации HTML, который не чувствителен к пробелам". В моем oponion это совершенно неправильно. HTML очень чувствителен к пробелам, он просто не важно, сколько их там. Он очень заботится о том, есть ли пробелы или нет.

некоторые мой вопрос: есть ли какой-либо разумный способ решить эту проблему в целом? (Тот, который всегда работает, а не только в некоторых ситуациях.)

(любые исправления на основе CSS не учитываются. Копировать / вставлять сюрпризы-это зло.)

2 ответов


Я считаю, что одним из решений является использование 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()

у меня сейчас нет Джанго-проекта передо мной, так что это непроверено.


Это лучшее, что я придумал до сих пор. Я все еще надеюсь на лучшее решение, но пока это будет сделано.

Я определил пользовательский фильтр, как это в база / templatetags / basetags.yp (из этого ответа):

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>