New to HTMX and Django, what I'm trying to achieve is to have a ModelForm on the page with a button that allows the user to 'Edit' the field values directly on the page. After pressing the 'edit' button, the page should display a 'cancel' and 'submit' button. It's basically the same as this example on the HTMX website: Edit Row
View on the index page:
Here's what I have so far (when user presses 'Edit Entry') but it's not working as intended:
There are a few issues:
When the 'edit' button is pressed, the ModelForm is loading everything into the first column of the HTML table. Ideally, I would want each field of the Model to be in the 'correct' location in the table.
When the 'cancel edit' button is pressed, it's swapping the ModelForm back to the HTML template. I don't want this but just want the table row to go back to how it was previously.
The submit button is not posting the data back to the Model.
I'm not sure how to really think about the design here to make the HTML table and ModelForm work as desired (#1 and #2).
For #3, the issue seems to be that the PUT request.method is coming back as an empty QuerySet.
Thanks for any help that can be offered. Once I get this working, I'll upload a brief video to YouTube to help out other beginners as couldn't find any examples online outside of the documentation for this simple implmentation.
Base HTML Template
<!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 template
{% 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)
For partial rendering of edit row you should not extend the whole base.html. That is causing problems #1 and #2. Here partial rendering with django and htmx is nicely explained.
For #3 submitting the data you are missing hx-include="closest tr"
on your submit button. See the demo page you linked and check hx params on submit button. That way your inputs are picked up from the row, without it and without form it just issues empty put.