Dynamische Webentwicklung mit Django und HTMX vereinfachen (Teil 4): Wie werden Payloads gesendet?
Im Gegensatz zu herkömmlichen Ajax-Anfragen mit fetch in JavaScript, bei denen man für POST-Anfragen den Payload oft direkt mit JSON.stringify() zusammenstellt, wie zum Beispiel:
fetch("/api/todos/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrftoken
},
body: JSON.stringify({
title: "장보기",
done: false,
priority: 3
})
})
Wie handhabt das HTMX? Wie genau sendet hx-post Daten an den Server? Da viele Beispiele nur sehr einfache Funktionen zeigen, ist es überraschend schwer, praktische Beispiele für die Übertragung komplexer Payloads zu finden.
Dieser Beitrag wird die Datenübertragungsarten in HTMX und deren Verarbeitung auf dem Server vollständig erläutern.

HTMX-Datenübertragungsarten
Der Ansatz für den Payload bei fetch und die Datenübertragungsart von hx-post unterscheiden sich erheblich.
Bei fetch erstellt der Entwickler direkt ein Objekt und wandelt es in JSON um, das dann in den Body gelegt wird. HTMX hingegen sammelt grundsätzlich Werte aus dem DOM und sendet diese.
Die Denkweise von HTMX ist nicht, „JS-Objekte direkt zusammenzustellen“, sondern „Werte aus HTML-Elementen zu sammeln, um Anfrageparameter zu erstellen“. Dafür werden üblicherweise die folgenden drei Methoden verwendet:
1) Werte über Formulare sammeln und senden
Dies ist die HTML-konformste Methode und passt gut zu Django.
<form hx-post="/todos/create/" hx-target="#todo-list">
<input type="text" name="title" placeholder="제목">
<input type="number" name="priority" value="3">
<input type="hidden" name="done" value="false">
<button type="submit">등록</button>
</form>
In diesem Fall sammelt HTMX die Eingabewerte innerhalb des Formulars und sendet sie in der Anfrage. Die Standardkodierung ist URL-encoded form data, genau wie bei einer normalen Formularübermittlung.
In einer Django-View kann man sie wie gewohnt empfangen:
def create_todo(request):
title = request.POST.get("title")
priority = request.POST.get("priority")
done = request.POST.get("done")
2) Werte anderer Elemente ohne Formular einbeziehen: hx-include
Dies wird verwendet, wenn man hx-post an einen einzelnen Button anfügt und nur bestimmte, weiter entfernte Eingabewerte mitsenden möchte.
<input type="text" id="title" name="title" placeholder="제목">
<input type="number" id="priority" name="priority" value="3">
<button hx-post="/todos/create/"
hx-include="#title, #priority"
hx-target="#todo-list">
등록
</button>
hx-include fügt die Werte der angegebenen Elemente der Anfrage hinzu. Man muss nicht das gesamte Element in <form> einschließen, um ein ähnliches Ergebnis wie einen Payload zu erzielen, was bei wenigen Eingabefeldern sehr nützlich ist.
3) Versteckte oder berechnete Werte hinzufügen: hx-vals
Dies ist die Funktion, die dem Konzept am nächsten kommt, einen Teil des Payload-Objekts direkt in fetch zu erstellen.
<button hx-post="/todos/create/"
hx-vals='{"title": "장보기", "done": false, "priority": 3}'
hx-target="#todo-list">
빠른 등록
</button>
hx-vals fügt der Anfrage zusätzliche Parameter hinzu. Standardmäßig wird die obige JSON-Syntax verwendet, aber mit dem Präfix js: können auch dynamische JavaScript-berechnete Werte gesendet werden.
<input type="text" id="title" placeholder="제목">
<button hx-post="/todos/create/"
hx-vals='js:{title: document.querySelector("#title").value, done: false, priority: 3}'
hx-target="#todo-list">
등록
</button>
Auch in diesem Fall liest Django die Werte über request.POST. Denn hx-vals definiert Werte in einer JSON-ähnlichen Syntax, macht aber den Anfragetext selbst nicht zu JSON.
Wichtiger Hinweis: hx-vals ist kein "JSON Payload"
Dies ist der verwirrendste Punkt, wenn man HTMX zum ersten Mal begegnet.
<button hx-post="/my-url/" hx-vals='{"a":1, "b":2}'>
Dieser Code bedeutet nicht, dass ein „JSON-Objekt als Body gesendet wird“, sondern eher, dass a=1&b=2 zu den Anfrageparametern hinzugefügt wird. Das bedeutet, der Server muss die Daten immer noch wie Formulardaten verarbeiten.
Was, wenn man wirklich einen JSON-Body senden möchte?
Wenn man unbedingt das application/json-Format wie bei fetch(... JSON.stringify(payload)) verwenden muss, benötigt man die json-enc-Erweiterung von HTMX.
Man konfiguriert sie gemäß der offiziellen Dokumentation wie folgt:
<script src="https://unpkg.com/htmx.org@1.9.12/dist/ext/json-enc.js"></script>
<button hx-post="/api/todos/"
hx-ext="json-enc"
hx-vals='{"title": "장보기", "done": false, "priority": 3}'
hx-target="#result">
JSON로 전송
</button>
Jetzt erst wird es zu unserer bekannten JSON-Payload-Methode. In diesem Fall ist request.POST in der Django-View leer, daher muss man request.body direkt lesen.
import json
def create_todo_api(request):
data = json.loads(request.body)
title = data.get("title")
# ... 로직 처리 ...
return JsonResponse({"ok": True})
HTMX und DRF: Unterschiedliche Philosophien, aber keine Notwendigkeit zur Verschmelzung
Obwohl man JSON mithilfe der Erweiterung senden kann, bleibt die Frage, ob dies der HTMX-eigenen Art entspricht. Dies liegt daran, dass hier zwei Philosophien kollidieren: die „datenorientierte“ (DRF) und die „hypermedienorientierte“ (HTMX).
Wenn man sich entscheidet, HTMX richtig einzusetzen, muss man sich vielleicht vorübergehend von der datenorientierten Denkweise lösen. Werte über <form>, hx-include und hx-vals zu senden, und der Server empfängt diese über request.POST und gibt HTML-Snippets anstelle von JSON zurück – genau hier glänzt HTMX am meisten.
Was, wenn man auf DRF-Serialisierer nicht verzichten möchte?
Die Serialisierer von DRF sind wirklich mächtig. Sollte man dieses praktische Validierungstool aufgeben und sich mit dem mühsamen request.POST.get() zufriedengeben, nur weil man HTMX verwendet?
Glücklicherweise validieren DRF-Serialisierer nicht nur JSON, sondern auch Formulardaten hervorragend. Da dieser Teil den Rahmen sprengen würde, werden wir im nächsten Beitrag ausführlich die „Koexistenz von HTMX und DRF-Serialisierern“ behandeln.
Fazit
Die heutigen Inhalte lassen sich wie folgt zusammenfassen:
- HTMX sammelt Werte grundsätzlich aus dem DOM. Dies unterscheidet sich vom Ansatz von
fetch, bei dem das Payload-Objekt direkt zusammengestellt wird. - 3 Übertragungsarten:
<form>zum Senden des Ganzen,hx-includezum gezielten Einbeziehen von Werten,hx-valszum Hinzufügen von Werten. - Standardmäßig sind es Formulardaten. Vorsicht: Auch wenn
hx-valsJSON-Syntax verwendet, wird kein tatsächlicher JSON-Body gesendet. - Wenn JSON unbedingt erforderlich ist, verwenden Sie die
json-enc-Erweiterung. Es ist jedoch gut zu wissen, dass der eigentliche Charme von HTMX im Austausch von HTML-Fragmenten liegt.
Im nächsten Teil kommen wir mit Methoden zurück, um die Bequemlichkeit von DRF in HTMX zu integrieren!
Weitere Beiträge lesen
- Dynamische Webentwicklung mit Django und HTMX vereinfachen (Teil 1)
- Dynamische Webentwicklung mit Django und HTMX vereinfachen - Ajax (Teil 2)
- Dynamische Webentwicklung mit Django und HTMX vereinfachen (Teil 3): Django-Integration
- Dynamische Webentwicklung mit Django und HTMX vereinfachen (Teil 4): Payload-Übertragungsarten
- Dynamische Webentwicklung vereinfachen mit Django und HTMX: Einsatz von Form und Serializer
- Dynamische Webentwicklung mit Django und HTMX vereinfachen: Trigger im Einsatz