Evgenii Legotckoi
Evgenii Legotckoi08 лютого 2022 р. 06: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

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

  • Уцінка
  • MarkdownSubscript
  • Позначка Надіндекс

Можливо ще 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 хостинг.

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

i
  • 11 листопада 2024 р. 22:12

Freckles because of several brand names retin a, atralin buy generic priligy

Коментарі

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

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

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

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

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

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

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
i
innorwall13 листопада 2024 р. 23:03
Як зробити гру за допомогою Qt - Урок 3. Взаємодія з іншими об'єктами what is priligy tablets What happens during the LASIK surgery process
i
innorwall13 листопада 2024 р. 20:09
Використання змінних оголошених в CMakeLists.txt всередині C++ файлів where can i buy priligy online safely Tom Platz How about things like we read about in the magazines like roid rage and does that really
i
innorwall11 листопада 2024 р. 22:12
Django - Урок 055. Як написати функціонал auto populate field Freckles because of several brand names retin a, atralin buy generic priligy
i
innorwall11 листопада 2024 р. 18:23
QML - Підручник 035. Використання перерахувань в QML без C++ priligy cvs 24 Together with antibiotics such as amphotericin B 10, griseofulvin 11 and streptomycin 12, chloramphenicol 9 is in the World Health Organisation s List of Essential Medici…
i
innorwall11 листопада 2024 р. 15:50
Qt/C++ - Урок 052. Налаштування Qt Audio player в стилі AIMP It decreases stress, supports hormone balance, and regulates and increases blood flow to the reproductive organs buy priligy online safe Promising data were reported in a PDX model re…
Тепер обговоріть на форумі
i
innorwall14 листопада 2024 р. 00:39
добавить qlineseries в функции Listen intently to what Jerry says about Conditional Acceptance because that s the bargaining chip in the song and dance you will have to engage in to protect yourself and your family from AMI S…
i
innorwall11 листопада 2024 р. 10:55
Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
ИМ
Игорь Максимов03 жовтня 2024 р. 04:05
Реализация навигации по разделам Спасибо Евгений!

Слідкуйте за нами в соціальних мережах