Evgenii Legotckoi
Evgenii LegotckoiMay 17, 2023, 1:52 a.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


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(

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.


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(
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!


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

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

  • Result:70points,
  • Rating points1

Qt - Test 001. Signals and slots

  • Result:84points,
  • Rating points4
Last comments
kmssrFeb. 9, 2024, 5:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVADec. 25, 2023, 9:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
JonnyJoDec. 25, 2023, 7:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
GvozdikDec. 19, 2023, 8:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
NSProjectJune 23, 2024, 11:48 p.m.
добавить qlineseries в функции А куда собстаенно делся Евгений раз на сайте такой бордак творится?
BlinCTMay 5, 2024, 3:46 p.m.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiMay 3, 2024, 12:07 a.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
IscanderCheApril 30, 2024, 2:22 p.m.
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…
GarApril 22, 2024, 3:46 p.m.
Clipboard Как скопировать окно целиком в clipb?

Follow us in social networks