Evgenii Legotckoi
Evgenii LegotckoiMay 16, 2023, 3:52 p.m.

Django - Lesson 064. How to write a Python Markdown extension

On this site and a couple of other projects, I actively use markdown to write text, and then generate html code from it. And in the end, I wrote a couple of extensions that perform some specific functionality, which somewhat facilitates the support for generating html code on my projects.

For example, in one of the projects, images are added to the text that are added to the site and attached to the post. Accordingly, images have a specific url that nginx sends this image to. But I made the markdown image embed code look simpler for images that are uploaded to the site.

Image embed code description

That is, the image insertion code in this case looks like this

![](e272ed2bca9e46e8b017c20eddd1e5b2.webp)

In this code, there is only the name of the image file e272ed2bca9e46e8b017c20eddd1e5b2.webp . On the project where this is implemented, all images are loaded into one directory with a unique generated name using uuid, and the image is compressed and converted to WEBP format. You can learn more about how to do this in the article How to convert an image to WEBP format when saving to an ImageField .

So, when images are attached to a post, they are displayed on that project as a gallery under the text, but can also be added inside the post text. But in order not to confuse users with a long url to the image in markdown markup, and also to simplify further potential modification of image paths, a function was implemented to generate an html img tag from this simplified image code.

Adding python markdown extension

Generate html text with python markdown

The Python-Markdown package is used to generate the HTML. The generation code might look like this:

def generate_html(markdown_text):
    return markdown.markdown(
                markdown_text,
                extensions=['markdown.extensions.attr_list',
                            'markdown.extensions.tables',
                            'markdown.extensions.fenced_code',
                            'markdown.extensions.nl2br',
                            'markdown.extensions.toc'],
                output_format='html5'
            )

As you can see, when generating it is possible to enumerate extensions that can affect the result of code generation. It is in these extensions that we will add our extension.

Add extension

Let's say in a Django project we have an app called core. Let's create an extensions directory inside it with a __init__.py file that initializes the directory as a package, as well as a file with the name of the extension. It should look like this.

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

Image.py file

Now let's add the contents of the image.py file.

# -*- coding: utf-8 -*-

import markdown
from markdown.util import etree


class ImageExtension(markdown.Extension):

    def add_inline(self, md, name, klass, re):
        pattern = klass(re)
        pattern.md = md
        pattern.ext = self
        md.inlinePatterns.add(name, pattern, "<reference")

    def extendMarkdown(self, md, md_globals):
        self.add_inline(md, 'internal_image', InternalImage, r'!\[\]\((?P<internal_image>[a-zA-Z0-9]+).webp\)')


class InternalImage(markdown.inlinepatterns.Pattern):

    def handleMatch(self, m):
        return render_image(m.group('internal_image'))


def render_image(internal_image_name):
    img = etree.Element('img')
    img.set('src', '/media/photos/{}.webp'.format(internal_image_name))
    img.set('class', 'd-block mx-auto mw-100 mvh-75')
    return img


def makeExtension(**kwargs):
    return ImageExtension(**kwargs)

In this case, we are creating an ImageExtension extension that extends the Markdown markup using the InternalImage template.
This pattern is applied to all image tags that match the regular expression that is passed to the add_inline method, which ultimately adds the pattern to the list of patterns with the markdown code handler.

The makeExtension function is called under the hood of Python-Markdown and registers the extension.

Conclusion

As a final word, let's add your new extension to the generation of your html code.

def generate_html(markdown_text):
    return markdown.markdown(
                markdown_text,
                extensions=['core.extensions.image',
                            'markdown.extensions.attr_list',
                            'markdown.extensions.tables',
                            'markdown.extensions.fenced_code',
                            'markdown.extensions.nl2br',
                            'markdown.extensions.toc'],
                output_format='html5'
            )
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

ИМ
  • Oct. 5, 2024, 7:51 a.m.
  • (edited)

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

<ul>
    <li></li>
    <li></li>
</ul>

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

<ul class='my_ul_class'>
    <li class='my_li_class'></li>
    <li class='my_li_class'></li>
</ul>

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

Comments

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

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:80points,
  • Rating points4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
Last comments
ИМ
Игорь МаксимовNov. 22, 2024, 10:51 p.m.
Django - Tutorial 017. Customize the login page to Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiNov. 1, 2024, 12:37 a.m.
Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEOct. 19, 2024, 6:19 p.m.
Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовOct. 5, 2024, 5:51 p.m.
Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5July 5, 2024, 9:02 p.m.
QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiJune 25, 2024, 1:11 a.m.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Nov. 15, 2024, 5:04 p.m.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectJune 4, 2022, 1:49 p.m.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimOct. 25, 2024, 7:10 p.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Follow us in social networks