Evgenii Legotckoi
17 травня 2023 р. 01:52

Django - Урок 064. Як написати розширення для Python Markdown

Я активно використовую на цьому сайті і кілька інших проектів markdown розмітку для написання тексту, а потім генерую з нього html код. І в результаті я написав пару розширень, які виконують певний специфічний функціонал, який дещо полегшує підтримку генерування html коду на моїх проектах.

Наприклад, у одному з проектів до тексту додаються зображення, які додані на сайт і прикріплені до посту. Відповідно, у зображень є якийсь специфічний url, за яким nginx віддає це зображення. Але я зробив так, що markdown код вставки зображення виглядатиме більш просто для зображень, які завантажені на сайт.

Опис коду вставки зображення

Тобто код вставки зображення в даному випадку виглядає так

  1. ![](e272ed2bca9e46e8b017c20eddd1e5b2.webp)

У цьому коді є лише ім'я файлу зображення e272ed2bca9e46e8b017c20eddd1e5b2.webp . На тому проекті, де реалізовано всі зображення завантажуються на одну директорію з унікальним генерованим ім'ям за допомогою uuid, а також зображення стискається і конвертується у формат WEBP. Докладніше ви можете ознайомитися, як це зробити у статті Як конвертувати зображення у формат WEBP при збереженні у ImageField .

Так ось, коли зображення прикріплені до посту, вони на тому проекті відображаються у вигляді галереї під текстом, але можуть бути додані всередину тексту посту. Але щоб не бентежити користувачів довгим url до зображення в markdown розмітці, а також спростити подальшу потенційну модифікацію шляхів до зображення, був реалізований функціонал генерування html тега img з цього спрощеного коду зображення.

Додавання python markdown розширення

Генерування html тексту за допомогою python markdown

Для створення HTML використовується пакет Python-Markdown. Код генерування може виглядати так:

  1. def generate_html(markdown_text):
  2. return markdown.markdown(
  3. markdown_text,
  4. extensions=['markdown.extensions.attr_list',
  5. 'markdown.extensions.tables',
  6. 'markdown.extensions.fenced_code',
  7. 'markdown.extensions.nl2br',
  8. 'markdown.extensions.toc'],
  9. output_format='html5'
  10. )

Як бачите, при генеруванні можна перерахувати розширення, які можуть впливати на результат генерування коду. Саме в ці розширення ми і додаватимемо наше розширення.

Додаємо розширення

Допустимо у проекті на Django у нас є app з назвою core. Створимо в ньому каталог extensions з __init__.py файлом, який ініціалізує каталог як пакет, а також файл з назвою розширення. Це має виглядати так.

  • core/
    • extensions/
      • __init__.py
      • image.py

Файл Image.py

А тепер додамо вміст файлу image.py .

  1. # -*- coding: utf-8 -*-
  2.  
  3. import markdown
  4. from markdown.util import etree
  5.  
  6.  
  7. class ImageExtension(markdown.Extension):
  8.  
  9. def add_inline(self, md, name, klass, re):
  10. pattern = klass(re)
  11. pattern.md = md
  12. pattern.ext = self
  13. md.inlinePatterns.add(name, pattern, "<reference")
  14.  
  15. def extendMarkdown(self, md, md_globals):
  16. self.add_inline(md, 'internal_image', InternalImage, r'!\[\]\((?P<internal_image>[a-zA-Z0-9]+).webp\)')
  17.  
  18.  
  19. class InternalImage(markdown.inlinepatterns.Pattern):
  20.  
  21. def handleMatch(self, m):
  22. return render_image(m.group('internal_image'))
  23.  
  24.  
  25. def render_image(internal_image_name):
  26. img = etree.Element('img')
  27. img.set('src', '/media/photos/{}.webp'.format(internal_image_name))
  28. img.set('class', 'd-block mx-auto mw-100 mvh-75')
  29. return img
  30.  
  31.  
  32. def makeExtension(**kwargs):
  33. return ImageExtension(**kwargs)
  34.  

В даному випадку ми створюємо розширення ImageExtension , яке розширює Markdown розмітку за допомогою шаблону InternalImage .
Даний шаблон застосовується до всіх тегів зображення, які відповідають регулярному виразу, що передається до методу add_inline, який у результаті додає шаблон до списку шаблонів з обробником коду markdown.

Функція makeExtension викликається під капотом Python-Markdown та реєструє розширення.

Висновок

Як заключне слово додамо ваше нове розширення в генерування фашого html коду.

  1. def generate_html(markdown_text):
  2. return markdown.markdown(
  3. markdown_text,
  4. extensions=['core.extensions.image',
  5. 'markdown.extensions.attr_list',
  6. 'markdown.extensions.tables',
  7. 'markdown.extensions.fenced_code',
  8. 'markdown.extensions.nl2br',
  9. 'markdown.extensions.toc'],
  10. output_format='html5'
  11. )

Вам це подобається? Поділіться в соціальних мережах!

ИМ
  • 05 жовтня 2024 р. 16:51
  • (відредаговано)

Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку:

  1. <ul>
  2. <li></li>
  3. <li></li>
  4. </ul>

подменять ее на свою типа:

  1. <ul class='my_ul_class'>
  2. <li class='my_li_class'></li>
  3. <li class='my_li_class'></li>
  4. </ul>
Evgenii Legotckoi
  • 31 жовтня 2024 р. 23:37

Добрый день.
Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up