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>
Желаемое отображение в админ-панели (внимание только но форму ввода):
Т.е. мне хотелось бы заменить стандартное отображение поля модели в админ панели с 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 = 'Изображение'