Evgenii Legotckoi
Evgenii Legotckoi8 февраля 2022 г. 6:55

Django - Урок 055. Как написать функционал auto populate field

Очень давно хотел написать статью о том, как написать функционал auto populate field для проекта на Django . Это очень полезный функционал, который позволяет изменять содержимое других полей модели в Django при установке значение в то поле, в котором используется auto populate.

Во-первых, зачем это нужно? - Подобный функционал позволяет сократить размеры кода в тех местах, где нужно переписывать другие поля объекта, при их изменении. То есть, вам например не придется каждый раз переопределять метод save, чтобы переписать какое-то поле в случае изменения других полей объекта. Также использование auto populate в принципе более продвинутый и аккуратный способ управления моделями данных в Django.
А также подобный подход моет решить некоторые проблемы и улучшить работу сайта.


Описание подхода на примере markdown полей

Например такой подход я использую на этом сайте для написания контента комментариев и статей, и вообще во всех полях, где используется синтаксис markdown .

Как это работает?

  • Все модели данных имеют два поля content и content_markdown . Поле content_markdown управляет содержимым поля content . То есть в обычной ситуации пользователь не имеет доступа к редактирования содержимого поля content , он всегда редактирует только поле content_markdown .
  • Пользователь, создавая сообщение, редактирует поле content_markdown , которое автоматически генерирут html код из markdown разметки и записывает html в поле content .

Зачем это нужно?

Каждый сам выбирает, для чего ему использовать auto populate. Например, Вы можете автоматически генерировать thumbnail изображение из исходного изображения. Подобный функционал идеально подходит для таких действий.

А конкретно в моём случае получилось так, что я не нашёл подходящего функционала для генерирования html из markdown. Всё что я находил на тот момент, это библиотеки, которые генерировал html в runtime при каждой загрузке страницы с помощью шаблонных тегов. А подобный подход очень сильно снижает производительность сайта. Поэтому я для себя решил, что готов пожертвовать дисковым пространством ради производительности сайта. В конце концов десятикратное увеличение скорости загрузки страницы в некоторых случаях явно предпочтительнее, чем двойной объем занимаемого дискового пространства.

Реализация

Я представлю упрощенный код MarkdownField , который вы могли бы использовать у себя на сайте.

MarkdownField

MarkdownField будет наследоваться от стандартного TextField и будет получать в качестве аргумента имя поля, которое будет использовать для html контента. Это аргумент html_field .

Данное поле имеет метод set_html , который отвечает за генерирование html из markdown разметки, а также установку значения в поле html контента.

Важным моментом является подключение метода set_html к сигналу pre_save в методе contribute_to_class . Более ранний вариант, который я разрабатывал, имел такой недостаток, что при каждом запросе объекта вызывался метод генерирования html. Это была ошибка, которую я впоследствие обнаружил и исправил подобным образом. Теперь контент генерируется только в случае сохранения объекта.

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

from django.db import models
from django.db.models.signals import pre_save

from .utils import MarkdownWorker


class MarkdownField(models.TextField):
    """
    This field save markdown text with auto-populate text to html field.
    This field must be used with second text field for html content.
    """

    def set_html(self, instance=None, update_fields=None, **kwargs):
        value = getattr(instance, self.attname)
        if value and len(value) > 0:
            instance.__dict__[self.html_field] = MarkdownWorker(value).get_text()

    def contribute_to_class(self, cls, name, **kwargs):
        super().contribute_to_class(cls, name, **kwargs)
        pre_save.connect(self.set_html, sender=cls)

    def __init__(self, html_field=None, *args, **kwargs):
        self.html_field = html_field
        super().__init__(*args, **kwargs)

MarkdownWorker

Даннй класс отввечает за генерирование html контента из markdown разметки. В данном классе вы можете добавить свои любые дополнительные виды обработки из html, чтобы получить необходимы вам готовый результат. Например, вы можете удалять ссылки или изображения, которые, по вашему мнению, пользователь не может добавлять.

При создании объекта класса MarkdownWorker устанавливается текст для обработки, а далее вызывается метод, который преобразует текст в html.

Также в моём случае используются расширения для:

  • Генерирования таблиц
  • Поддержки кода
  • Добавления переноса
  • Верхнего и нижнего синтаксиса
# -*- coding: utf-8 -*-

import markdown

class MarkdownWorker:
    """
    Markdown converter. It will convert markdown text to html text
    """
    def __init__(self, text):
        self.pre_markdown_text = text
        self.markdown_text = None
        self.make_html_from_markdown()

    def make_html_from_markdown(self):
        if self.pre_markdown_text:
            self.markdown_text = markdown.markdown(
                self.pre_markdown_text,
                extensions=['markdown.extensions.attr_list',
                            'markdown.extensions.tables',
                            'markdown.extensions.fenced_code',
                            'markdown.extensions.nl2br',
                            'superscript',
                            'subscript'],
                output_format='html5'
            )

    def get_text(self):
        return self.markdown_text

Для поддержки всего этого функционала вам необходимо будет установить библиотеки:

  • Markdown
  • MarkdownSubscript
  • MarkdownSuperscript

Возможно ещё beautifulsoup4 , либо это установится в зависимостях, а так честно, не помню.

Применение

А теперь применим данное поле в модели данных.

У нас имеется модель Post, в которой находятся поля:

  • user - внешний ключ на пользователя
  • content - поле, в котором будет содержаться html контент
  • content_markdown - поле, в которое будет сохраняться markdown текст с последующей генерацией html текста. При этом вы видите, что в него передаётся аргумент html_field='content', который говорит, с каким полем предстоит работать MarkdownField.
# -*- coding: utf-8 -*-

from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

from .fields import MarkdownField


class Post(models.Model):
    user = models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    content = models.TextField(verbose_name=_('Description'))
    content_markdown = MarkdownField(verbose_name=_('Description - Markdown'), html_field='content')

Заключение

Таким образом вы сможете добавить на свой сайт markdown поля, которые будут автоматически генерировать html контент.
Теперь у вас будет поддержка модного markdown синтаксиса на вашем сайте, который автоматически создаст html контент.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
m
  • molni99
  • 26 октября 2024 г. 11:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 26 октября 2024 г. 11:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20баллов,
  • Очки рейтинга-10

C++ - Тест 003. Условия и циклы

  • Результат:42баллов,
  • Очки рейтинга-8
Последние комментарии
i
innorwall8 ноября 2024 г. 19:51
Django - Урок 036. Как добавить аутентификацию через социальные сети. ВКонтакте buy priligy online usa In addition, it might not be effective at the doses recommended, because of your previous tolerance to a similar type of drug
i
innorwall8 ноября 2024 г. 18:40
Qt/C++ - Урок 039. Как закрасить строку в QSqlTableModel по значению в столбце priligy results This slowing of eGFR decline was observed in patients with and without low eGFR and in those with and without type 2 diabetes
i
innorwall8 ноября 2024 г. 13:45
QML - Урок 002. Custom Button in QML Android 2007; 14 2 270 83 priligy dapoxetine 60mg Testicular imaging is sort of a unique niche right now, Гў
i
innorwall8 ноября 2024 г. 12:32
C++ - Ускоряет ли сборку #pragma once? It could cause harm to the unborn baby buy generic priligy
Сейчас обсуждают на форуме
i
innorwall8 ноября 2024 г. 18:08
добавить qlineseries в функции School of Nursing, Long Island University, Brooklyn Campus, Brooklyn, NY, USA priligy dapoxetine 30mg
9
9Anonim25 октября 2024 г. 19:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
ИМ
Игорь Максимов3 октября 2024 г. 14:05
Реализация навигации по разделам Спасибо Евгений!
F
Fynjy22 июля 2024 г. 14:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Следите за нами в социальных сетях