Блог на Django #29: Создание собственных шаблонных фильтров

63

В Django есть много разных встроенных фильтров, которые позволяют модифицировать переменные в шаблонах. Это функции Python, принимающие один или два параметра: значение переменной, к которой она будет применена и опциональный аргумент. Они возвращают значение, которое может быть отображено или стать еще одним фильтром. Фильтр выглядит следующим образом {{ variable|my_filter }}. А фильтры с аргументом так — {{ variable|my_filter:"foo" }}. К переменной можно применять сколько угодно фильтров, например, {{ variable|filter1|filter2 }}. Каждый из них будет применен в выводу, который сгенерирует предыдущий.

Создадим собственный фильтр, который позволит использовать разметку Markdown в постах блога и затем конвертировать содержимое в код HTML в шаблонах. Markdown — это синтаксис для форматирования обычного текста, который затем превращается в HTML. С основами этого формата можно ознакомиться по ссылке https://daringfireball.net/project/markdown/basics.

Сперва установите модуль Markdown в Python с помощью pip:

pip install Markdown==2.6.11

Затем отредактируйте файл blog_tags.py и добавьте следующий код:

from django.utils.safestring import mark_safe 
import markdown

@register.filter(name='markdown')  
def markdown_format(text):  
    return mark_safe(markdown.markdown(text))

Фильтры шаблона регистрируются так же, как и шаблонные теги. Чтобы избежать конфликта имени функции с модулем markdown первую нужно назвать markdown_format, а фильтр для шаблонов — markdown: {{ variable|markdown }}. Django исключает HTML-код, сгенерированный фильтрами. Функция mark_sage из Django используется, чтобы отметить, какой HTML-код нужно отрендерить стандартным путем. По умолчанию, Django будет исключать любой HTML-код перед выводом. Единственные исключения — отмеченные переменные. Такое поведение предотвращает возможный вывод потенциально опасного кода и позволяет создавать исключения для возврата безопасного HTML-кода.

Теперь загрузите шаблонные теги в шаблоны со списком постов и страницей поста. Добавьте следующую строку в верхней части шаблонов blog/post/list.html и blog/post/detail.html после тега {% extends %}:

{% load blog_tags %}

В шаблоне post/detail.html взгляните на следующую строку:

{{ post.body|linebreaks }}

Замените ее на эту:

{{ post.body|markdown }}

Затем в файле post/list.html замените эту строку:

{{ post.body|truncatewords:30|linebreaks }}

На эту:

{{ post.body|markdown|truncatewords_html:30 }}

Фильтр truncatewords_html обрезает строку после определенного количества слов, избегая незакрытых HTML-тегов.

Теперь откройте http://127.0.0.1:8000/admin/blog/post/add в браузере и добавьте пост со следующим тегом.

This is a post formatted with markdown
--------------------------------------

*This is emphasized* and **this is more emphasized**.

Here is a list:

* One
* Two
* Three

And a [link to the Django website](https://www.djangoproject.com/)

Откройте браузер и посмотрите, как он отрендерился. Должно выглядеть вот так:

Разметка Markdown в постах блога на Django

Как можно видеть на скриншоте, собственные фильтры шаблонов очень удобны для форматирования. Больше об этой теме здесь: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/#writing-custom-template-filters.

Тест на знание python

Что делает функция re.match()?
Что выведет этот код?
Какая из следующих функций проверяет, что все символы строки в верхнем регистре?
Какой будет результат выполнения кода — print(type(1J)) ?
Какой ввод НЕ приведет к ошибке?