Модальная форма django-ckeditor не изменяет данные при POST
У меня есть проект django, использующий django-ckeditor. Я использую HTMX для создания bootstrap-модала для отображения формы редактирования. Она отображается правильно (я добавил файлы ckeditor.js в конец тела в base.html). Если я вызываю свою форму, перейдя по адресу localhost/1/update, изменяю значение RTF и нажимаю сохранить, она работает нормально. Но если отобразить ее в модальной форме и нажать сохранить, то form.has_changed() возвращает false. Если я редактирую другое поле и сохраняю, значение RTF НЕ меняется. Похоже, что POST не включает измененное значение для поля CKEditor.
Я постарался сократить приведенный ниже код, чтобы сделать его как можно короче.
Моя модель:
class MyModel(models.Model):
name = models.CharField(max_length=50)
description = models.CharField(max_length=150)
comment = RichTextField(blank=True, null=True)
def __str__(self):
return f'{self.name} - {self.description}'
Моя форма:
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = (
'name',
'description',
'comment',
)
Мое мнение
def update_data(request, pk):
model = MyModel.objects.get(id=pk)
form = MyForm(request.POST or None, instance=model)
if request.method == "POST":
if form.is_valid():
print(form.has_changed())
form.save()
return redirect("detail-form", pk=model.id)
Мой HTML#1 - я нажимаю на кнопку обновления, чтобы открыть модальное окно
{% extends "layouts/base.html" %}
{% load static %}
{% block content %}
<main>
<div class="section section-md pt-4">
<div class="container">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody id="myforms">
{% for entry in entries %}
<tr id="entryform_{{entry.id}}">
<td>
<h4 class="h5">{{ entry.name }}</h4>
</td>
<td>
<h4 class="h5">{{ entry.description }}</h4>
</td>
<td style="width: 200px">
<button hx-get="{% url 'update-entry' entry.id %}" hx-swap="outerHTML"
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Update
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div id="modals-here"></div>
</main>
{% endblock content %}
{% block javascripts %}
<script>
function closeModal() {
var container = document.getElementById("modals-here")
var backdrop = document.getElementById("modal-backdrop")
var modal = document.getElementById("modal")
modal.classList.remove("show")
backdrop.classList.remove("show")
setTimeout(function() {
container.removeChild(backdrop)
container.removeChild(modal)
}, 200)
}
</script>
{% endblock javascripts %}
и затем последний html, модель формы. Обратите внимание, что я добавил {{ form.media }}
<div id="modal-backdrop" class="modal-backdrop fade show" style="display:block;"> </div>
<div id="modal" class="modal fade show" tabindex="-1" style="display:block;">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body">
<form method="post">
{% csrf_token %}
{{ form.media }}
{{ form.as_p|safe }}
<button type="submit" hx-post="{% url 'update-data' entry.id %}" hx-target="#entryform_{{entry.id}}" hx-swap="outerHTML"
class="btn btn-primary" onclick="closeModal()">
Submit
</button>
</form>
</div>
</div>
</div>
</div>
Есть совет? Интуиция подсказывает, что это как-то связано с тем, что редактор загружается только после того, как страница уже загружена. Если я помню, у меня была похожая проблема несколько лет назад с JS-выбором даты. Не могу вспомнить, как я тогда это исправил.
Проблема была не в модальном коде. Проблема возникла из-за HTMX. Это всегда будет проблемой при использовании HTMX с RTF редакторами, и я думаю, что это решение будет работать во всех случаях. Я нашел похожую проблему с tinyMCE с решением для tinyMCE here. Моя реализация с CKEditor представляет собой следующий код:
<div id="modal-backdrop" class="modal-backdrop fade show"
style="display:block;"> </div>
<div id="modal" class="modal fade show" tabindex="-1" style="display:block;">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body">
<form method="post">
{% csrf_token %}
{{ form.media }}
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
var element = new CKEDITOR.dom.element( document.getElementById( '{{ form.comment.id_for_label }}' ) );
event.detail.parameters['{{ form.comment.html_name }}'] = element.getEditor().getData();
})
</script>
{{ form.as_p|safe }}
<button type="submit" hx-post="{% url 'update-data' entry.id %}" hx-target="#entryform_{{entry.id}}" hx-swap="outerHTML"
class="btn btn-primary" onclick="closeModal()">
Submit
</button>
</form>
</div>
</div>
</div>
</div>
Возможно, это не самое лучшее место для размещения скрипта, но он прекрасно там работает. Это место также позволяет сделать его более универсальным с помощью тегов формы.