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

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

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

философия

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

Система шаблонов Django предоставляет теги, функции которых аналогичны некоторым программным структурам (тег if для логических тестов, тег for для циклов и т. Д.), Но они выполняются не только как код Python. корреспондент; Система шаблонов Django не выполняет просто какие-либо выражения 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 }} title section

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

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

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

Фильтры

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

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

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

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

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

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

default

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

{{ value|default:"nothing" }}

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

length

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

{{ value|length }}

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

filesizeformat

Форматирует значение как удобочитаемый размер файла (например , и т. Д.). Например :'13 Kio' '4.1 Mio' '102 octets'

{{ value|filesizeformat }}

ЕСЛИ value содержит 123456789, результат будет .117.7 Mio

Это всего лишь несколько примеров; см. полный список в справочнике по встроенным фильтрам .

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

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

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

Теги

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

Некоторые теги требуют открывающего и закрывающего тегов (например ).{% tag %} ... contenu de la balise ... {% endtag %}

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

for

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

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

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

{% 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_NOMSECTION.html для каждого раздела сайта. Например base_actualites.html , base_sports.html . Все эти шаблоны расширяют base.html и содержат определенный стиль и внешний вид раздела.
  • Создавайте индивидуальные шаблоны для каждого типа страницы, например для новостной статьи или сообщения в блоге. Эти шаблоны расширяют шаблон раздела, в котором они появляются.

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

Вот несколько советов по наследованию:

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

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

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

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

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

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

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

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

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

Наконец, обратите внимание, что вы не можете определить несколько тегов block с одним и тем же именем в одном шаблоне. Это ограничение существует, потому что маяк 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 }}

safe (Safe на английском языке) может использоваться как сокращение для 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

Буквальный текст и автоматическое экранирование

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

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

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

Это означает, что вам нужно написать:

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

…и нет :

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

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

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

Большинство вызовов методов, связанных с объектами, также доступны из шаблонов. Это означает, что шаблоны не только имеют доступ к атрибутам класса (например, именам полей) или переменным, передаваемым из представлений. Например, ORM Django предлагает синтаксис 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" %} humanize {% load humanize %}

Это добровольное поведение для лучшего обслуживания и чистоты кода.

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

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

Copyright ©2020 All rights reserved