Django admin panel. MathQuill. Как настроить своё (кастомное) отображение формы, представляющей поле модели?

Предисловие

Здравствуйте. По учёбе создаю веб-приложение на django. Я, так сказать, в этом деле новичок, поэтому столкнулся с проблемой при настройке админ панели.


Суть проблемы

Имеется модель Tasks(models.Model) со своими полями. Конкретно по данной теме меня интересует только поле latex. На данный момент оно имеет следующий вид: latex = models.TextField(blank=True, verbose_name='Формула (LaTeX)'). И отображается в админ панели как textarea. Для моего приложения это очень плохой вариант.

Как вы уже могли догадаться из названия, в поле latex подразумевается ввод каких-либо формул в одноимённом формате. Например, \left(\sqrt{a}\right)^m=\sqrt{a^m}. В данном же виде и должно храниться введённое содержимое в базе данных. Но вводить в обычную textarea это неудобно. На помощь приходит инструмент MathQuill (http://mathquill.com/).

Пример использования:

<p>Type math here: <span id="math-field"></span></p>
<p>LaTeX of what you typed: <span id="latex"></span></p>

<script>
var mathFieldSpan = document.getElementById('math-field');
var latexSpan = document.getElementById('latex');

var MQ = MathQuill.getInterface(2); // for backcompat
var mathField = MQ.MathField(mathFieldSpan, {
  spaceBehavesLikeTab: true, // configurable
  handlers: {
    edit: function() { // useful event handlers
      latexSpan.textContent = mathField.latex(); // simple API
    }
  }
});
</script>

Желаемое отображение в админ-панели (внимание только но форму ввода): mathquill_form.jpg

Т.е. мне хотелось бы заменить стандартное отображение поля модели в админ панели с textarea на своё - mathquill.


Вопрос

Как грамотно реализовать желаемое?

Я пока пришёл к следующему: нужно создать файл widgets.py в приложении, в этом файле прописать свой виджет, к которому необходимо подключить html файл с макетом MathQuill; затем - создать в каком-нибудь файлике fields.py новый класс поля, например, LatexField, который использовал бы вышеописанный виджет для отображения; и уже в модели Tasks (а позже и в других моделях) изменить строку latex = models.TextField(blank=True, verbose_name='Формула (LaTeX)') на latex = models.LatexField(blank=True, verbose_name='Формула (LaTeX)').

Но это всё в теории. Как же подойти к этому на практике - понятия не имею.


Код

models.py

class Tasks(models.Model):
    subject_fk = models.ForeignKey(Subjects, on_delete=models.CASCADE, verbose_name='Ключ предмета')
    num = models.SmallIntegerField(default=1, validators=[MinValueValidator(1)], verbose_name='Номер задания в тесте')
    text = models.TextField(blank=True, verbose_name='Текст задания')
    latex = models.TextField(blank=True, verbose_name='Формула (LaTeX)')
    image = models.ImageField(blank=True, upload_to='thumbnails_task/', verbose_name='Изображение')

    def __str__(self):
        return str(self.id)

    class Meta:
        verbose_name = 'Задание'
        verbose_name_plural = 'Задания'
        ordering = ['subject_fk', 'num']

admin.py

class TasksForm(forms.ModelForm):
    def clean(self):
        if 'num' in self.cleaned_data:
            num = self.cleaned_data['num']
            if 'subject_fk' in self.cleaned_data:
                subj_id = self.cleaned_data['subject_fk'].id
                t_num = Subjects.objects.get(id=subj_id).tasks_number
                if num <= t_num:
                    if self.cleaned_data['text'] == '' and self.cleaned_data['latex'] == '' \
                            and (self.cleaned_data['image'] is None or self.cleaned_data['image'] is False):
                        raise forms.ValidationError({
                            'text': 'Хотя бы одно из полей "{}", "{}", "{}" должно быть заполнено.'.format(
                                Tasks._meta.get_field('text').verbose_name,
                                Tasks._meta.get_field('latex').verbose_name,
                                Tasks._meta.get_field('image').verbose_name)})
                else:
                    raise forms.ValidationError(
                        {'num': 'Убедитесь, что это значение меньше либо равно {}.'.format(t_num)})
            else:
                raise forms.ValidationError(
                    {'num': 'Для начала укажите "{}".'.format(Tasks._meta.get_field('subject_fk').verbose_name)})
        else:
            raise forms.ValidationError({'num': 'Убедитесь, что вы заполнили это поле.'})


class TasksAdmin(admin.ModelAdmin):
    form = TasksForm

    list_display = ('id', 'subject_fk', 'num', 'text', 'latex', 'get_html_img')
    list_display_links = ('id',)
    list_filter = ('subject_fk',)
    search_fields = ('=num',)

    def get_html_img(self, object):
        if object.image:
            return mark_safe('<img src="{}" style="max-width:100%">'.format(object.image.url))

    get_html_img.short_description = 'Изображение'

Изображение

admin_panel.jpg

Вернуться на верх