HTMX + Django - Редактирование формы модели в таблице HTML

Новичок в HTMX и Django, я пытаюсь добиться того, чтобы иметь ModelForm на странице с кнопкой, которая позволяет пользователю "редактировать" значения полей прямо на странице. После нажатия кнопки "редактировать" на странице должны отображаться кнопки "отмена" и "отправить". По сути, это то же самое, что и пример на сайте HTMX: Edit Row

  • Отмена должна отменить изменения и показать таблицу снова (как было)
  • Submit должен опубликовать внесенные изменения обратно в модель
  • .

Просмотр на индексной странице:

enter image description here


Вот что у меня есть на данный момент (когда пользователь нажимает 'Edit Entry'), но это не работает так, как задумано:

enter image description here

Есть несколько вопросов:

  1. Когда нажата кнопка "редактировать", ModelForm загружает все в первый столбец таблицы HTML. В идеале, я бы хотел, чтобы каждое поле модели находилось в "правильном" месте в таблице.

  2. Когда нажимается кнопка 'cancel edit', она меняет ModelForm обратно на шаблон HTML. Я не хочу этого, а просто хочу, чтобы строка таблицы вернулась в прежнее состояние.

  3. Кнопка submit не посылает данные обратно в модель.


Я не уверен, как действительно продумать дизайн здесь, чтобы HTML-таблица и ModelForm работали так, как нужно (#1 и #2).

Для #3 проблема, похоже, заключается в том, что PUT request.method возвращается как пустой QuerySet.

Спасибо за любую помощь, которая может быть предложена. Как только у меня все заработает, я загружу короткое видео на YouTube, чтобы помочь другим новичкам, так как не смог найти никаких примеров в сети за пределами документации для этой простой имплантации.


Базовый HTML шаблон

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>

    <!-- HTMX -->
    <script src="https://unpkg.com/htmx.org@1.8.0" integrity="sha384-cZuAZ+ZbwkNRnrKi05G/fjBX+azI9DNOkNYysZ0I/X5ZFgsmMiBXgDZof30F5ofc" crossorigin="anonymous"></script>

</head>

{% block page_content %}

<body>

    <table class="country_table">
        <thead>
            <tr>
                <th> City Name </th>
                <th> Country </th>
                <th> Latitude </th>
                <th> Longitude </th>
                <th> </th>
            </tr>
        </thead>
        <tbody hx-target="closest tr" hx-swap="outer HTML">
            {% for city in city_model %}
            <tr>
                <td> {{city.city_name}}</td>
                <td> {{city.city_country}}</td>
                <td> {{city.city_latitude}}</td>
                <td> {{city.city_longitude}}</td>
                <td> <button class="btn btn-danger"
                    hx-get="{% url 'edit_city_record' city.city_name %}"
                    hx-trigger="click"> Edit Entry </button> </td>
            </tr>
            {%endfor%}
        </tbody>
    </table>

</body>

{% endblock page_content %}

</html>

<script>
    document.body.addEventListener('htmx:configRequest', (event) => {
    event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}'; })    
</script>

шаблон edit_city_record.html

{% extends 'base_html.html' %}

{% block page_content %}

<tr>
    <td> {{city_form.city_name}} </td>
    <td> {{city_form.city_country}} </td>
    <td> {{city_form.city_latitude}} </td>
    <td> {{city_form.city_longitude}} </td>
   
    <td> <button class="btn btn-danger"
        hx-get="{% url 'get_city_record' city_object.city_name %}"
        hx-trigger="click"> Cancel Edit </button> </td>

    <td> 
        <button class="btn btn-danger"
        type="submit"
        hx-put="{% url 'edit_city_record' city_object.city_name %}"
        hx-trigger="click"> Save Edit </button> 

    </td>

</tr>

{% endblock page_content %}

get_city_record.py template

{% extends 'base_html.html' %}
{% block page_content %}
     {{city_form}}
{% endblock page_content %}

views.py

from django.shortcuts import render

from main_app.models import cityModel
from main_app.forms import cityModelForm

def index(request):

    city_model = cityModel.objects.all()

    context = {'city_model': city_model}
    return render(request, 'base_html.html', context)


def edit_city_record(request, city_name):
    print(request.method)
    city_object = cityModel.objects.get(city_name=city_name) 
    
    if request.method == 'PUT':
        city_form = cityModelForm(request.POST, instance=city_object)
        print(request.POST)

        if city_form.is_valid():
            city_form.save()

    else:
        city_form = cityModelForm(instance=city_object)

    context = {'city_form': city_form, 'city_object': city_object}
    return render(request, 'edit_city_record.html', context)


def get_city_record(request, city_name):
    city_object = cityModel.objects.get(city_name=city_name)
    city_form = cityModelForm(instance=city_object)
    context = {'city_form': city_form}
    return render(request, 'get_city_record.html', context) 

Для частичного отображения строки редактирования не следует расширять весь файл base.html. Это вызывает проблемы #1 и #2. Здесь хорошо объясняется частичный рендеринг с помощью django и htmx.

Для #3 отправки данных вам не хватает hx-include="closest tr" на вашей кнопке отправки. Посмотрите демо-страницу, на которую вы дали ссылку, и проверьте hx-параметры на кнопке submit. Таким образом ваши входные данные подхватываются из строки, без этого и без формы она просто выдает пустой put.

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