Evgenij LegotskojFeb. 8, 2022, 5:55 a.m.

Django - Tutorial 055. How to write auto populate field functionality

For a long time I wanted to write an article on how to write auto populate field functionality for a Django project. This is a very useful feature that allows you to change the content of other model fields in Django by setting a value to a field that uses auto populate.

First, why is it needed? - Such functionality allows you to reduce the size of the code in those places where you need to rewrite other fields of the object when they change. That is, for example, you do not have to redefine the save method each time in order to rewrite some field in case other fields of the object change. Also, using auto populate is basically a more advanced and neat way to manage data models in Django.
And also a similar approach can solve some problems and improve the site.

Description of the approach using markdown fields as an example

For example, I use this approach on this site for writing the content of comments and articles, and in general in all fields where the markdown syntax is used.

How it works?

  • All data models have two fields content and content_markdown . The content_markdown field controls the content of the content field. That is, in a normal situation, the user does not have access to edit the contents of the content field, he always edits only the content_markdown field.
  • The user, when creating a message, edits the content_markdown field, which automatically generates html code from the markdown markup and writes html in the content field.

Why is this needed?

Everyone chooses for himself why he should use auto populate. For example, you can automatically generate a thumbnail image from a source image. Such functionality is ideal for such actions.

And specifically in my case, it turned out that I did not find a suitable functionality for generating html from markdown. All I found at that time were libraries that generated html at runtime on every page load using template tags. And this approach greatly reduces the performance of the site. Therefore, I decided for myself that I was ready to sacrifice disk space for the sake of website performance. After all, a tenfold increase in page load speed is in some cases clearly preferable to double the amount of disk space occupied.

Implementation

I will present a simplified MarkdownField code that you could use on your site.

MarkdownField

MarkdownField will inherit from the standard TextField and will take as an argument the name of the field to use for html content. This is the html_field argument.

This field has a set_html method which is responsible for generating html from the markdown markup and also setting the value in the html field of the content.

The important point is to connect the set_html method to the pre_save signal in the contribute_to_class method. An earlier version I developed had the disadvantage that every time an object was requested, the html-generating method was called. It was a bug that I subsequently discovered and corrected in a similar way. Now the content is generated only if the object is saved.

# -*- 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

This class is responsible for generating html content from markdown markup. In this class, you can add any additional types of processing from html to get the finished result you need. For example, you can remove links or images that you don't think the user can add.

When creating an object of the MarkdownWorker class, the text to be processed is set, and then a method is called that converts the text to html.

Also in my case, extensions are used for:

  • Table generation
  • Code support
  • Transfer Additions
  • Upper and lower syntax
# -*- 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

To support all this functionality, you will need to install the libraries:

  • Markdown
  • MarkdownSubscript
  • MarkdownSuperscript

Maybe also beautifulsoup4 , or it will be installed in dependencies, but honestly, I don’t remember.

Application

And now let's apply this field in the data model.

We have a Post model that contains the fields:

  • user - foreign key per user
  • content - field that will contain html content
  • content_markdown - the field where the markdown text will be saved with subsequent generation of html text. In doing so, you can see that the html_field='content' argument is passed to it, which tells which field the MarkdownField is to work with.
# -*- 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')

Conclusion

This way you can add markdown fields to your site that will automatically generate html content.
You will now have support for fancy markdown syntax on your site, which will automatically generate html content.

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.
- company blog
Support the author Donate

Comments

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

Let me recommend you a great European Fornex hosting.

Fornex has proven itself to be a stable host over the years.

For Django projects I recommend VPS hosting

Following the link you will receive a 5% discount on shared hosting services, dedicated servers, VPS and VPN

View Hosting
Share on social networks
Donate

The EVILEG project has switched to a non-commercial basis and will develop solely on the enthusiasm of the site creator, the enthusiasm of users, donations and the hosting referral system

Thank you for your support

Available ways to support the project

PayPal

PatreonYandex.MoneyMore
AB

C++ - Test 006. Enumerations

  • Result:30points,
  • Rating points-10
MH

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

  • Result:42points,
  • Rating points-8
AB

C++ - Test 005. Structures and Classes

  • Result:50points,
  • Rating points-4
Popular publications in the last 90 Days
Last comments

EVILEG-CORE. Caching properties of model objects using model_cached_property

Здравствуйте. В общем меня интересует такой вопрос. Я пробовал это на Like , Dislike. Как я понимаю если не перевалидировать кеш то ничего не изменится на странице. Вернётся значение из кэша? От…
A

Qt/C++ - Lesson 006. QSqlQueryModel – Tables in Qt with SQL-query

Здравствуйте! Подскажите как сделать запрос к базе SQLite с двумя параметрами, в итоге нужно получить не список строк, а только факт наличия строк, соответсвующи именно двум условиям. В SQL…
A

Django - Tutorial 011. Adding comments to the site based on Django

https://mir74.ru/27323-12-krasavic-sdelali-podarok-stalnomu-gigantu.-rabotnicy-mmk-snyalis-dlya-yubileynogo-fotokalendarya.html
a

Django - Tutorial 011. Adding comments to the site based on Django

I read that Post and got it fine and informative.https://aflife.ru/

Django - Tutorial 023. Like Dislike system using GenericForeignKey

Хорошо. Большое спасибо. Посмотрю что из этого получится.
Now discuss on the forum
o

Запрос на изменение БД с помощью оператора UPDATE и странное поведение QTableView

или запрос к базе так https://www.w3schools.com/sql/sql_ref_order_by.asp или сортировка в модели через прокси модель https://doc.qt.io/qt-5/qsortfilterproxymodel.html
o

Как очичтисть очередь событий для конпки

нужно сделать связку qml и c++, тяжелые задачи отправляются на обработку в с++, в qml остаются только быстрые. и у кнопок есть свойство enabled: true\false при запуске\остановке з…
A

Развертывание QML приложения

Полностью согласен, что пример не удачный, но я так как раз попытался выразить то, что вы далее описали с примером со скадой, часть .dll и часть .qml с интерпритацией. И в Вашем ответе я ув…
AB

Sorting the added QML elements in the ListModel

I am writing an alarm clock in QML, I am required to sort the alarms in ascending order (depending on the date or time (if there are several alarms on the same day). I've done the sorting …
EK

HTTP server на Qt

Давно было, уже не помню как, но разрулил. Спасибо :)
About
Services
© EVILEG 2015-2022
Recommend hosting TIMEWEB