HTMX + Django - Редактирование формы модели в таблице HTML
Новичок в HTMX и Django, я пытаюсь добиться того, чтобы иметь ModelForm на странице с кнопкой, которая позволяет пользователю "редактировать" значения полей прямо на странице. После нажатия кнопки "редактировать" на странице должны отображаться кнопки "отмена" и "отправить". По сути, это то же самое, что и пример на сайте HTMX: Edit Row
- Отмена должна отменить изменения и показать таблицу снова (как было)
- Submit должен опубликовать внесенные изменения обратно в модель .
Просмотр на индексной странице:
Вот что у меня есть на данный момент (когда пользователь нажимает 'Edit Entry'), но это не работает так, как задумано:
Есть несколько вопросов:
Когда нажата кнопка "редактировать", ModelForm загружает все в первый столбец таблицы HTML. В идеале, я бы хотел, чтобы каждое поле модели находилось в "правильном" месте в таблице.
Когда нажимается кнопка 'cancel edit', она меняет ModelForm обратно на шаблон HTML. Я не хочу этого, а просто хочу, чтобы строка таблицы вернулась в прежнее состояние.
Кнопка 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.