Dynamische webontwikkeling vereenvoudigen met Django en HTMX (deel 4): Hoe zit het met de payload?

Bij Ajax-verzoeken met de bestaande JavaScript fetch sturen we bij een POST-verzoek meestal de payload direct samen, vaak met JSON.stringify().

Het werkt ongeveer zo:

fetch("/api/todos/", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-CSRFToken": csrftoken
  },
  body: JSON.stringify({
    title: "장보기",
    done: false,
    priority: 3
  })
})

Hoe zit dat dan met HTMX? Hoe verstuurt hx-post eigenlijk data naar de server? Veel voorbeelden tonen alleen zeer eenvoudige functionaliteiten, waardoor het verrassend moeilijk is om praktische voorbeelden te vinden voor het versturen van complexe payloads.

In dit bericht zullen we de methoden voor dataoverdracht in HTMX en hoe de server deze verwerkt, volledig uitleggen.

Schematische weergave van de HTMX-gegevensstroom in DJANGO


Dataoverdrachtsmethoden van HTMX



De payload-benadering van fetch en de dataoverdrachtsmethode van hx-post zijn behoorlijk verschillend.

Bij fetch maakt de ontwikkelaar zelf een object en converteert dit naar JSON om het in de body te plaatsen. HTMX daarentegen verzamelt in principe waarden uit de DOM en stuurt deze door.

De denkwijze van HTMX is niet zozeer "JS-objecten direct samenstellen", maar eerder "waarden uit HTML-elementen verzamelen om verzoekparameters te creëren". Hiervoor worden doorgaans de volgende drie methoden gebruikt:

1) Waarden verzenden op basis van een formulier

Dit is de meest HTML-vriendelijke en goed aansluitende methode voor 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 dit geval verzamelt HTMX de invoerwaarden binnen het formulier en voegt deze toe aan het verzoek. De standaardcodering is URL-encoded form data, net als bij een reguliere formulierinzending.

In een Django-view ontvang je dit zoals gewoonlijk:

def create_todo(request):
    title = request.POST.get("title")
    priority = request.POST.get("priority")
    done = request.POST.get("done")

2) Waarden van andere elementen opnemen zonder formulier: hx-include

Dit gebruik je wanneer je een hx-post aan een knop wilt koppelen en tegelijkertijd specifieke, verderop gelegen invoerwaarden wilt meesturen.

<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 voegt de waarden van de gespecificeerde elementen toe aan het verzoek. Je hoeft niet de hele sectie in een <form> te wikkelen om een vergelijkbaar resultaat als een payload te bereiken, wat erg handig is bij weinig invoervelden.

3) Verborgen of berekende waarden toevoegen: hx-vals

Dit is de functionaliteit die het dichtst in de buurt komt van het direct samenstellen van een deel van de payload in fetch.

<button hx-post="/todos/create/"
        hx-vals='{"title": "장보기", "done": false, "priority": 3}'
        hx-target="#todo-list">
    빠른 등록
</button>

hx-vals voegt extra parameters toe aan het verzoek. Standaard wordt de JSON-syntaxis zoals hierboven gebruikt, maar met het voorvoegsel js: kun je ook dynamisch berekende JavaScript-waarden versturen.

<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>

Ook in dit geval leest Django de waarden via request.POST. Dit komt omdat hx-vals "waarden definieert met een JSON-achtige syntaxis", maar niet de verzoekbody zelf in JSON-formaat maakt.


Belangrijk: hx-vals is niet hetzelfde als een "JSON Payload"

Dit is het meest verwarrende aspect wanneer je voor het eerst met HTMX werkt.

<button hx-post="/my-url/" hx-vals='{"a":1, "b":2}'>

Deze code betekent niet dat een "JSON-object als body wordt verzonden", maar eerder dat a=1&b=2 aan de verzoekparameters wordt toegevoegd. De server moet dit dus nog steeds behandelen als formulierdata.

Echt een JSON-body versturen?

Als je per se het application/json-formaat wilt gebruiken, zoals bij fetch(... JSON.stringify(payload)), dan heb je de json-enc extensie van HTMX nodig.

Volg de instructies in de officiële documentatie om dit in te stellen:

<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>

Nu pas verkrijgen we de vertrouwde JSON-payloadmethode. In dit geval zal request.POST in de Django-view leeg zijn, dus moet je request.body direct uitlezen.

import json

def create_todo_api(request):
    data = json.loads(request.body)
    title = data.get("title")
    # ... logica verwerken ...
    return JsonResponse({"ok": True})

HTMX en DRF hebben een filosofische kloof, maar hoeven niet per se te worden samengevoegd.



Hoewel je JSON kunt versturen met een extensie, blijft de vraag of dit wel de HTMX-manier is. Dit komt omdat twee filosofieën hier botsen: "datacentrisch (DRF)" en "hypermedia-centrisch (HTMX)".

Als je besluit HTMX correct te gebruiken, moet je wellicht even afstand nemen van de datacentrische denkwijze. Waarden versturen met <form>, hx-include, hx-vals, en de server laten reageren met HTML-snippets in plaats van JSON via request.POST – dat is waar HTMX het meest tot zijn recht komt.

Wat als DRF-serializers te waardevol zijn om op te geven?

De serializers van DRF zijn ongelooflijk krachtig. Moeten we dit handige validatiehulpmiddel opgeven en terugvallen op het handmatig request.POST.get() gedoe als we HTMX gebruiken?

Gelukkig kunnen DRF-serializers niet alleen JSON, maar ook formulierdata uitstekend valideren. Omdat dit onderwerp te uitgebreid is voor dit bericht, zullen we in het volgende deel dieper ingaan op de "co-existentie van HTMX en DRF-serializers".


Conclusie

De belangrijkste punten van vandaag zijn:

  1. HTMX verzamelt in principe waarden uit de DOM. De aanpak verschilt van fetch, waarbij je direct payload-objecten samenstelt.
  2. Drie overdrachtsmethoden: <form> voor de hele set, hx-include om specifieke elementen te kiezen, en hx-vals om extra waarden toe te voegen.
  3. De standaard is formulierdata. Let op: zelfs als hx-vals JSON-syntaxis gebruikt, betekent dit niet dat de werkelijke JSON-body wordt verzonden.
  4. Als JSON absoluut noodzakelijk is, gebruik dan de json-enc extensie. Maar onthoud dat de essentie van HTMX ligt in het uitwisselen van HTML-fragmenten.

Volgende keer komen we terug met methoden om het gemak van DRF in HTMX te integreren!

Gerelateerde artikelen