Язык шаблонов Django

В этом документе объясняется синтаксис языка системы шаблонов Django. Если вы ищете более технический взгляд на то, как это работает и как его расширить, см. Язык шаблонов Django: для программистов Python .

Язык шаблонов Django разработан для достижения баланса между мощностью и простотой. Он разработан, чтобы чувствовать себя комфортно для тех, кто привык работать с HTML. Если вы знакомы с другими языками текстовых шаблонов, такими как Smarty или Jinja2 , вы должны чувствовать себя как дома с шаблонами Django.

Философия

Если у вас есть опыт программирования или вы привыкли к языкам, которые смешивают программный код непосредственно с HTML, вы должны иметь в виду, что система шаблонов Django - это не просто Python, встроенный в HTML. Это сделано намеренно: система шаблонов предназначена для выражения представления, а не логики программы.

Система шаблонов Django предоставляет теги, которые работают аналогично некоторым программным конструкциям - ifтег для логических тестов, for тег для цикла и т. Д. - но они не просто выполняются как соответствующий код Python, и система шаблонов не будет выполнять произвольные выражения Python. . По умолчанию поддерживаются только теги, фильтры и синтаксис, перечисленные ниже (хотя при необходимости вы можете добавить свои собственные расширения к языку шаблона).

Шаблоны

Шаблон - это текстовый файл. Он может генерировать любой текстовый формат (HTML, XML, CSV и т. Д.).

Шаблон содержит переменные , которые заменяются значениями при оценке шаблона, и теги , которые управляют логикой шаблона.

Ниже приведен минимальный шаблон, иллюстрирующий некоторые основы. Каждый элемент будет объяснен позже в этом документе.

{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}

Философия

Зачем использовать текстовый шаблон вместо XML (например, TAL от Zope)? Мы хотели, чтобы язык шаблонов Django можно было использовать не только для шаблонов XML / HTML. Вы можете использовать язык шаблона для любого текстового формата, такого как электронная почта, JavaScript и CSV.

Переменные

Переменные выглядят следующим образом : . Когда механизм шаблонов встречает переменную, он оценивает эту переменную и заменяет ее результатом. Имена переменных состоят из любой комбинации буквенно-цифровых символов и символа подчеркивания ( ), но не могут начинаться с подчеркивания и не могут быть числом. Точка ( ) также появляется в разделах переменных, хотя это имеет особое значение, как указано ниже. Важно отметить, что в именах переменных не должно быть пробелов или знаков препинания.{{ variable }}"_""."

Используйте точку ( .) для доступа к атрибутам переменной.

За кулисами

Технически, когда система шаблонов встречает точку, она пытается выполнить следующие поиски в следующем порядке:

  • Поиск по словарю
  • Поиск атрибута или метода
  • Поиск по числовому индексу

Если результирующее значение можно вызвать, оно вызывается без аргументов. Результат вызова становится значением шаблона.

Этот порядок поиска может вызвать непредвиденное поведение с объектами, которые переопределяют поиск по словарю. Например, рассмотрим следующий фрагмент кода, который пытается перебрать collections.defaultdict:

{% for k, v in defaultdict.items %}
    Do something with k and v here...
{% endfor %}

Поскольку сначала выполняется поиск по словарю, это поведение срабатывает и предоставляет значение по умолчанию вместо использования предполагаемого .items()метода. В этом случае сначала подумайте о преобразовании в словарь.

В приведенном выше примере будет заменен атрибутом объекта.{{ section.title }}titlesection

Если вы используете переменную, которой не существует, система шаблонов вставит значение string_if_invalidпараметра, для которого ''по умолчанию установлено значение (пустая строка).

Обратите внимание, что «bar» в выражении шаблона, например, будет интерпретироваться как буквальная строка и не будет использовать значение переменной «bar», если она существует в контексте шаблона.{{ foo.bar }}

Доступ к переменным атрибутам, начинающимся с символа подчеркивания, недоступен, поскольку они обычно считаются частными.

Фильтры

Вы можете изменять переменные для отображения с помощью фильтров .

Фильтры выглядеть следующим образом : . Здесь отображается значение переменной после фильтрации через фильтр, который преобразует текст в нижний регистр. Используйте вертикальную черту ( ), чтобы применить фильтр.{{ name|lower }}{{ name }}lower|

Фильтры можно «связать». Выходные данные одного фильтра применяются к следующему. - это обычная идиома для экранирования текстового содержимого с последующим преобразованием разрывов строк в теги.{{ text|escape|linebreaks }}<p>

Некоторые фильтры принимают аргументы. Фильтр аргумент выглядит следующим образом : . Это отобразит первые 30 слов переменной.{{ bio|truncatewords:30 }}bio

Аргументы фильтра, содержащие пробелы, должны быть заключены в кавычки; например, чтобы присоединиться к списку с запятыми и пробелами, которые вы бы использовали .{{ list|join:", " }}

Django предоставляет около шестидесяти встроенных шаблонных фильтров. Вы можете прочитать все о них во встроенном справочнике по фильтрам . Чтобы дать вам представление о том, что доступно, вот некоторые из наиболее часто используемых шаблонных фильтров:

default

Если переменная ложна или пуста, используйте данное значение по умолчанию. В противном случае используйте значение переменной. Например:

{{ value|default:"nothing" }}

Если valueне указан или пуст, в приведенном выше сообщении будет отображаться « nothing».

length

Возвращает длину значения. Это работает как для строк, так и для списков. Например:

{{ value|length }}

Если valueесть , то вывод будет .['a', 'b', 'c', 'd']4

filesizeformat

Форматы значение как размер файла «читабельной» (то есть , , и т.д.). Например:'13 KB''4.1 MB''102 bytes'

{{ value|filesizeformat }}

Если value123456789, вывод будет .117.7 MB

Опять же, это всего лишь несколько примеров; полный список см. в справочнике по встроенным фильтрам .

Вы также можете создавать свои собственные фильтры шаблонов; см. Пользовательские теги и фильтры шаблонов .

Смотрите также

Интерфейс администратора Django может включать в себя полную ссылку на все теги шаблонов и фильтры, доступные для данного сайта. См . Генератор документации администратора Django .

Теги

Теги выглядеть следующим образом : . Теги более сложны, чем переменные: некоторые создают текст в выходных данных, некоторые управляют потоком, выполняя циклы или логику, а некоторые загружают внешнюю информацию в шаблон для использования последующими переменными.{% tag %}

Для некоторых тегов требуются начальные и конечные теги (т.е. ).{% tag %} ... tag contents ... {% endtag %}

Django поставляется с двумя десятками встроенных тегов шаблонов. Вы можете прочитать все о них во встроенной справке по тегам . Чтобы дать вам представление о том, что доступно, вот некоторые из наиболее часто используемых тегов:

for

Переберите каждый элемент в массиве. Например, чтобы отобразить список спортсменов, представленный в athlete_list:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>
if, elifИelse

Оценивает переменную, и если эта переменная имеет значение «истина», отображается содержимое блока:

{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
    Athletes should be out of the locker room soon!
{% else %}
    No athletes.
{% endif %}

В приведенном выше примере, если athlete_listне пусто, количество спортсменов будет отображаться переменной. В противном случае, если не пусто, отобразится сообщение «Спортсмены должны выйти…». Если оба списка пусты, «Спортсменов нет». будет отображаться.{{ athlete_list|length }}athlete_in_locker_room_list

Также в ifтеге можно использовать фильтры и различные операторы :

{% if athlete_list|length > 1 %}
   Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
   Athlete: {{ athlete_list.0.name }}
{% endif %}

Хотя приведенный выше пример работает, имейте в виду, что большинство шаблонных фильтров возвращают строки, поэтому математические сравнения с использованием фильтров, как правило, не будут работать так, как вы ожидаете. lengthэто исключение.

block а также extends
Настройте наследование шаблонов (см. Ниже), мощный способ сократить количество «шаблонов» в шаблонах.

Опять же, приведенное выше - это лишь выборка всего списка; полный список см. в справочнике по встроенным тегам .

Вы также можете создавать собственные настраиваемые теги шаблонов; см. Пользовательские теги и фильтры шаблонов .

Смотрите также

Интерфейс администратора Django может включать в себя полную ссылку на все теги шаблонов и фильтры, доступные для данного сайта. См . Генератор документации администратора Django .

Комментарии

Чтобы закомментировать часть строки в шаблоне, используйте комментарий синтаксис: .{# #}

Например, этот шаблон будет отображаться как 'hello':

{# greeting #}hello

Комментарий может содержать любой код шаблона, недействительный или нет. Например:

{# {% if foo %}bar{% else %} #}

Этот синтаксис можно использовать только для однострочных комментариев (символы новой строки между разделителями {#и не допускаются #}). Если вам нужно закомментировать многострочную часть шаблона, см. commentТег.

Наследование шаблонов

Самая мощная и, следовательно, самая сложная часть шаблонизатора Django - это наследование шаблонов. Наследование шаблонов позволяет вам создать базовый «скелетный» шаблон, который содержит все общие элементы вашего сайта и определяет блоки, которые дочерние шаблоны могут переопределить.

Давайте посмотрим на наследование шаблонов, начав с примера:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css">
    <title>{% block title %}My amazing site{% endblock %}</title>
</head>

<body>
    <div id="sidebar">
        {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
        {% endblock %}
    </div>

    <div id="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

Этот шаблон, который мы назовем base.html, определяет скелет HTML-документа, который вы можете использовать для страницы с двумя столбцами. Задача «дочерних» шаблонов - заполнить пустые блоки содержимым.

В этом примере blockтег определяет три блока, которые могут быть заполнены дочерними шаблонами. Все, что blockделает тег, - это сообщает механизму шаблонов, что дочерний шаблон может переопределить эти части шаблона.

Дочерний шаблон может выглядеть так:

{% extends "base.html" %}

{% block title %}My amazing blog{% endblock %}

{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>
    <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

extendsТег является ключевым здесь. Он сообщает механизму шаблонов, что этот шаблон «расширяет» другой шаблон. Когда система шаблонов оценивает этот шаблон, сначала она находит родительский объект - в данном случае «base.html».

В этот момент механизм шаблонов заметит три blockтега base.htmlи заменит эти блоки содержимым дочернего шаблона. В зависимости от значения blog_entriesрезультат может выглядеть так:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css">
    <title>My amazing blog</title>
</head>

<body>
    <div id="sidebar">
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    </div>

    <div id="content">
        <h2>Entry one</h2>
        <p>This is my first entry.</p>

        <h2>Entry two</h2>
        <p>This is my second entry.</p>
    </div>
</body>
</html>

Обратите внимание: поскольку дочерний шаблон не определял sidebarблок, вместо него используется значение из родительского шаблона. Содержимое тега в родительском шаблоне всегда используется как резерв.{% block %}

Вы можете использовать столько уровней наследования, сколько необходимо. Один из распространенных способов использования наследования - это следующий трехуровневый подход:

  • Создайте base.htmlшаблон, который отражает основной внешний вид вашего сайта.
  • Создайте base_SECTIONNAME.htmlшаблон для каждого «раздела» вашего сайта. Так , например, base_news.html, base_sports.html. Все эти шаблоны расширяют base.htmlи включают стили / дизайн для конкретных разделов.
  • Создавайте индивидуальные шаблоны для каждого типа страницы, например для новостной статьи или записи в блоге. Эти шаблоны расширяют соответствующий шаблон раздела.

Такой подход максимизирует повторное использование кода и помогает добавлять элементы в области общего содержимого, например навигацию по разделу.

Вот несколько советов по работе с наследованием:

  • Если вы используете в шаблоне, это должен быть первый тег шаблона в этом шаблоне. В противном случае наследование шаблонов работать не будет.{% extends %}

  • Чем больше тегов в ваших базовых шаблонах, тем лучше. Помните, что дочерние шаблоны не обязательно должны определять все родительские блоки, поэтому вы можете указать разумные значения по умолчанию в нескольких блоках, а затем определять только те, которые вам понадобятся позже. Лучше иметь больше крючков, чем меньше.{% block %}

  • Если вы обнаружите, что дублируете контент в нескольких шаблонах, это, вероятно, означает, что вам следует переместить этот контент в родительский шаблон.{% block %}

  • Если вам нужно получить содержимое блока из родительского шаблона, переменная сделает свое дело. Это полезно, если вы хотите добавить к содержимому родительского блока, а не полностью его переопределить. Данные, вставленные с помощью , не будут автоматически экранированы (см. Следующий раздел ), поскольку они уже были экранированы, если необходимо, в родительском шаблоне.{{ block.super }}{{ block.super }}

  • Используя то же имя шаблона, что и вы наследуете, его можно использовать для наследования шаблона одновременно с его переопределением. В сочетании с этим это может быть мощным способом внесения небольших изменений. См. Полный пример в разделе « Расширение переопределенного шаблона» в инструкции по переопределению шаблонов .{% extends %}{{ block.super }}

  • Переменные, созданные вне a с использованием синтаксиса тега шаблона, не могут использоваться внутри блока. Например, этот шаблон ничего не отображает:{% block %}as

    {% translate "Title" as title %}
    {% block content %}{{ title }}{% endblock %}
    
  • Для дополнительного удобства чтения можно при желании дать имя вашему тегу. Например:{% endblock %}

    {% block content %}
    ...
    {% endblock content %}
    

    В больших шаблонах этот метод помогает увидеть, какие теги закрываются.{% block %}

Наконец, обратите внимание, что вы не можете определить несколько blockтегов с одним и тем же именем в одном шаблоне. Это ограничение существует, потому что тег блока работает «в обоих» направлениях. То есть тег блока не просто предоставляет дыру для заполнения - он также определяет контент, который заполняет дыру в родительском элементе . Если бы blockв шаблоне было два тега с одинаковыми именами , родительский элемент этого шаблона не знал бы, какой из содержимого блоков использовать.

Автоматическое экранирование HTML

При создании HTML из шаблонов всегда существует риск того, что переменная будет включать символы, влияющие на результирующий HTML. Например, рассмотрим этот фрагмент шаблона:

Hello, {{ name }}

Сначала это кажется безобидным способом отображения имени пользователя, но подумайте, что произойдет, если пользователь введет свое имя следующим образом:

<script>alert('hello')</script>

С этим значением имени шаблон будет отображаться как:

Hello, <script>alert('hello')</script>

… Что означает, что в браузере появится всплывающее окно с предупреждением JavaScript!

Точно так же что, если имя содержит такой '<'символ?

<b>username

В результате получится такой шаблон, как это:

Hello, <b>username

… Что, в свою очередь, приведет к тому, что оставшаяся часть веб-страницы будет выделена жирным шрифтом!

Ясно, что отправленным пользователем данным не следует слепо доверять и вставлять их прямо на ваши веб-страницы, потому что злоумышленник может использовать такую ​​дыру для потенциально плохих вещей. Этот тип эксплойта безопасности называется атакой с межсайтовым скриптингом (XSS).

Чтобы избежать этой проблемы, у вас есть два варианта:

  • escapeВо- первых, вы можете убедиться, что каждая ненадежная переменная пропущена через фильтр (описанный ниже), который преобразует потенциально опасные символы HTML в опасные. Это было решение по умолчанию в Django в течение первых нескольких лет, но проблема в том, что оно возлагает бремя на вас , разработчика / автора шаблона, чтобы убедиться, что вы избегаете всего. Легко забыть об экранировании данных.
  • Во-вторых, вы можете воспользоваться автоматическим экранированием HTML в Django. В оставшейся части этого раздела описывается, как работает автоматическое экранирование.

По умолчанию в Django каждый шаблон автоматически экранирует вывод каждого тега переменной. В частности, эти пять символов экранированы:

  • < конвертируется в &lt;
  • > конвертируется в &gt;
  • ' (одинарная кавычка) преобразуется в &#x27;
  • " (двойная кавычка) преобразуется в &quot;
  • & конвертируется в &amp;

Опять же, мы подчеркиваем, что это поведение включено по умолчанию. Если вы используете систему шаблонов Django, вы защищены.

Как выключить

Если вы не хотите, чтобы данные автоматически экранировались на уровне сайта, шаблона или переменной, вы можете отключить его несколькими способами.

Почему вы хотите его выключить? Потому что иногда, переменные шаблона содержат данные , которые вы собираетесь быть отображены в качестве исходного HTML, в этом случае вы не хотите их содержимое , чтобы быть экранированы. Например, вы можете сохранить в своей базе данных кусок HTML-кода и захотеть встроить его прямо в свой шаблон. Или вы можете использовать систему шаблонов Django для создания текста, который не является HTML - например, сообщения электронной почты.

Для отдельных переменных

Чтобы отключить автоматическое экранирование для отдельной переменной, используйте safe фильтр:

This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}

Думайте о безопасном как о сокращении для защиты от дальнейшего экранирования или его можно безопасно интерпретировать как HTML . В этом примере, если он dataсодержит '<b>', вывод будет следующим:

This will be escaped: &lt;b&gt;
This will not be escaped: <b>

Для шаблонных блоков

Чтобы управлять автоматическим экранированием для шаблона, оберните шаблон (или определенный раздел шаблона) в autoescapeтег, например:

{% autoescape off %}
    Hello {{ name }}
{% endautoescape %}

autoescapeТег принимает либо onили в offкачестве аргумента. Иногда вам может потребоваться принудительное автоматическое экранирование, когда в противном случае оно было бы отключено. Вот пример шаблона:

Auto-escaping is on by default. Hello {{ name }}

{% autoescape off %}
    This will not be auto-escaped: {{ data }}.

    Nor this: {{ other_data }}
    {% autoescape on %}
        Auto-escaping applies again: {{ name }}
    {% endautoescape %}
{% endautoescape %}

Тег с автоматическим экранированием передает свой эффект на шаблоны, которые расширяют текущий, а также на шаблоны, включенные с помощью includeтега, как и все теги блоков. Например:

base.html
{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}
child.html
{% extends "base.html" %}
{% block title %}This &amp; that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}

Поскольку автоматическое экранирование отключено в базовом шаблоне, оно также будет отключено в дочернем шаблоне, что приведет к отображению следующего HTML-кода, когда greetingпеременная содержит строку <b>Hello!</b>:

<h1>This &amp; that</h1>
<b>Hello!</b>

Примечания

Как правило, авторам шаблонов не нужно особо беспокоиться об автоматическом экранировании. Разработчики на стороне Python (люди, пишущие представления и настраиваемые фильтры) должны подумать о случаях, в которых данные не следует экранировать, и соответствующим образом пометить данные, чтобы в шаблоне все работало.

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

Строковые литералы и автоматическое экранирование

Как мы упоминали ранее, аргументы фильтра могут быть строками:

{{ data|default:"This is a string literal." }}

Все строковые литералы вставляются в шаблон без какого-либо автоматического экранирования - они действуют так, как если бы все они были пропущены через safe фильтр. Причина этого заключается в том, что автор шаблона контролирует то, что входит в строковый литерал, поэтому он может убедиться, что текст правильно экранирован при записи шаблона.

Это означает, что вы напишете

{{ data|default:"3 &lt; 2" }}

…скорее, чем:

{{ data|default:"3 < 2" }}  {# Bad! Don't do this. #}

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

Доступ к вызовам методов

Большинство вызовов методов, прикрепленных к объектам, также доступны из шаблонов. Это означает, что шаблоны имеют доступ к гораздо большему, чем просто атрибуты класса (например, имена полей) и переменные, передаваемые из представлений. Например, Django ORM предоставляет синтаксис entry_set для поиска коллекции объектов, связанных с внешним ключом. Следовательно, учитывая модель под названием «комментарий» с отношением внешнего ключа к модели под названием «задача», вы можете просмотреть все комментарии, прикрепленные к данной задаче, следующим образом:

{% for comment in task.comment_set.all %}
    {{ comment }}
{% endfor %}

Точно так же QuerySets предоставляет count()метод для подсчета количества содержащихся в них объектов. Таким образом, вы можете получить количество всех комментариев, относящихся к текущей задаче, с помощью:

{{ task.comment_set.all.count }}

Вы также можете получить доступ к методам, которые вы явно определили в своих собственных моделях:

models.py
class Task(models.Model):
    def foo(self):
        return "bar"
template.html
{{ task.foo }}

Поскольку Django намеренно ограничивает объем логической обработки, доступной в языке шаблонов, невозможно передавать аргументы в вызовы методов, доступные из шаблонов. Данные должны вычисляться в представлениях, а затем передаваться в шаблоны для отображения.

Пользовательские библиотеки тегов и фильтров

Некоторые приложения предоставляют настраиваемые библиотеки тегов и фильтров. Чтобы получить к ним доступ в шаблоне, убедитесь, что приложение находится в INSTALLED_APPS(мы добавили бы 'django.contrib.humanize'для этого примера), а затем используйте load тег в шаблоне:

{% load humanize %}

{{ 45000|intcomma }}

В приведенном выше loadтеге загружается humanizeбиблиотека тегов, которая затем делает intcommaфильтр доступным для использования. Если вы включили django.contrib.admindocs, вы можете проконсультироваться с областью документации в вашем администраторе, чтобы найти список настраиваемых библиотек в вашей установке.

loadТег может иметь несколько имен библиотек, разделенных пробелами. Пример:

{% load humanize i18n %}

См. Раздел Пользовательские теги и фильтры шаблонов для получения информации о написании собственных библиотек пользовательских шаблонов.

Пользовательские библиотеки и наследование шаблонов

Когда вы загружаете настраиваемый тег или библиотеку фильтров, теги / фильтры становятся доступными только для текущего шаблона, а не для родительских или дочерних шаблонов по пути наследования шаблона.

Например, если у шаблона foo.htmlесть , дочерний шаблон (например, тот, у которого есть ) не будет иметь доступа к тегам и фильтрам гуманизированного шаблона. Дочерний шаблон отвечает за свой собственный .{% load humanize %}{% extends "foo.html" %}{% load humanize %}

Это функция ради ремонтопригодности и здравомыслия.

Смотрите также

Справочник по шаблонам
Охватывает встроенные теги, встроенные фильтры, использование альтернативного языка шаблонов и многое другое.

Copyright ©2021 All rights reserved