Модальная форма 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>

Возможно, это не самое лучшее место для размещения скрипта, но он прекрасно там работает. Это место также позволяет сделать его более универсальным с помощью тегов формы.

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