# Django와 HTMX로 동적 웹 개발을 단순화하기 (4편) : payload는 어떻게? 기존 자바스크립트의 `fetch`를 이용한 Ajax 요청에서는 POST 요청을 보낼 때, 보통 `JSON.stringify()`를 이용해 페이로드(payload)를 직접 조립해서 보냅니다. 대략 이런 감각이죠. ```JavaScript fetch("/api/todos/", { method: "POST", headers: { "Content-Type": "application/json", "X-CSRFToken": csrftoken }, body: JSON.stringify({ title: "장보기", done: false, priority: 3 }) }) ``` 그렇다면 **[[HTMX]]**에서는 어떨까요? 도대체 `hx-post`는 데이터를 어떤 식으로 서버에 보내는 걸까요? 많은 예제가 아주 단순한 기능만 보여주다 보니, 복잡한 페이로드를 만들어 보내는 실전 예제를 찾기가 의외로 힘듭니다. 이번 포스트에서는 [[HTMX]]에서의 데이터 전송 방식과 서버에서 이를 처리하는 법을 완전히 정리해 보겠습니다. ![DJANGO에서 HTMX데이터의 흐름 도식화](/media/whitedec/blog_img/fbe9c41ba8ea4eabb78e760e1f768482.webp) ------ ## HTMX의 데이터 전송 방식 {#sec-1f930b1a0dad} **`fetch`의 페이로드 감각과 `hx-post`의 데이터 전송 방식은 꽤 다릅니다.** `fetch`에서는 개발자가 직접 객체를 만들고 JSON으로 변환해 바디(body)에 넣습니다. 반면 **HTMX는 기본적으로 DOM에 있는 값들을 수집해서 전송**합니다. HTMX의 사고방식은 "JS 객체를 직접 조립하는 것"이 아니라, **"HTML 요소에서 값들을 모아 요청 파라미터를 만드는 것"**에 가깝습니다. 이를 위해 보통 다음 3가지 방식을 사용합니다. ### 1) Form 기반으로 값 모아서 보내기 {#sec-f5086851ac19} 가장 HTML답고 Django에도 잘 맞는 방식입니다. ```html
``` 이 경우 HTMX는 폼 안의 입력값들을 수집해서 요청에 담아 보냅니다. 기본 인코딩은 일반 폼 제출과 같은 **URL-encoded form data** 방식입니다. Django 뷰에서는 평소처럼 이렇게 받으면 됩니다. ```Python def create_todo(request): title = request.POST.get("title") priority = request.POST.get("priority") done = request.POST.get("done") ``` ### 2) Form 없이 다른 요소의 값 포함하기: `hx-include` {#sec-a2c0e1f9e1ca} 버튼 하나에 `hx-post`를 달면서, 멀리 떨어져 있는 입력값만 골라 같이 보내고 싶을 때 사용합니다. ```HTML ``` `hx-include`는 지정한 요소들의 값을 요청에 포함시킵니다. 굳이 전체를 `
`으로 감싸지 않아도 페이로드와 비슷한 결과물을 만들 수 있어, 입력 항목이 적을 때 매우 유용합니다. ### 3) 숨겨진 값이나 계산된 값 추가하기: `hx-vals` {#sec-f3e44212771a} 이게 바로 `fetch`에서 페이로드 객체를 일부 직접 만드는 개념과 가장 가까운 기능입니다. ```HTML ``` `hx-vals`는 요청에 추가 파라미터를 넣습니다. 기본은 위처럼 JSON 문법을 쓰지만, `js:` 접두사를 붙이면 동적인 자바스크립트 계산값도 보낼 수 있습니다. ```HTML ``` 이 경우도 Django에서는 `request.POST`로 읽습니다. `hx-vals`는 **"JSON처럼 생긴 문법으로 값을 정의"**하는 것이지, 요청 본문 자체를 JSON으로 만드는 것은 아니기 때문입니다. ------ ## 주의할 점: `hx-vals`는 "JSON Payload"와 다릅니다 {#sec-c31077e0c2ea} HTMX를 처음 접할 때 가장 헷갈리는 부분입니다. ```HTML ``` 이제야 비로소 우리가 익숙한 JSON 페이로드 방식이 됩니다. 이때 Django 뷰에서는 `request.POST`가 비어있으므로, `request.body`를 직접 읽어야 합니다. ```Python import json def create_todo_api(request): data = json.loads(request.body) title = data.get("title") # ... 로직 처리 ... return JsonResponse({"ok": True}) ``` ------ ## HTMX와 DRF는 철학의 갭이 있지만 합쳐질 필요도 없다. {#sec-aff378931c81} 확장팩을 써서 JSON을 보낼 수는 있지만, 과연 이것이 HTMX다운 방식인가 하는 의문은 남습니다. 이는 **"데이터 중심(DRF)"**과 **"하이퍼미디어 중심(HTMX)"**이라는 두 철학이 충돌하는 지점이기 때문입니다. [[HTMX]]를 제대로 쓰기로 했다면, 어쩌면 데이터 중심의 사고방식에서 잠시 벗어날 필요가 있다고 생각합니다. ``, `hx-include`, `hx-vals`로 값을 보내고, 서버는 `request.POST`로 이를 받아 **JSON이 아닌 HTML 스니펫을 반환하는 것**. 그 자체가 HTMX가 가장 빛나는 지점입니다. ### 하지만 DRF 시리얼라이저는 포기하기 아깝다면? {#sec-2a26aeec3b61} DRF의 시리얼라이저는 정말 강력합니다. HTMX를 쓴다고 해서 이 편리한 유효성 검사 도구를 버리고 `request.POST.get()` 노가다를 해야 할까요? 다행히 DRF 시리얼라이저는 JSON뿐만 아니라 폼 데이터도 기가 막히게 검증해 줍니다. 이 부분은 내용이 길어질 것 같아, 다음 편에서 **"HTMX와 DRF 시리얼라이저의 공존"**에 대해 깊이 다뤄보도록 하겠습니다. ------ ## 마무리 {#sec-ab81cf195815} 오늘 내용을 요약하자면 다음과 같습니다. 1. **HTMX는 기본적으로 DOM에서 값을 수집합니다.** 직접 페이로드 객체를 짜는 `fetch`와는 접근 방식이 다릅니다. 2. **전송 방식 3가지:** 전체를 보내는 ``, 골라서 보내는 `hx-include`, 값을 추가하는 `hx-vals`. 3. **기본은 폼 데이터입니다.** `hx-vals`가 JSON 문법을 쓴다고 해서 실제 JSON body로 가는 것은 아니니 주의하세요. 4. **JSON이 꼭 필요하다면 `json-enc` 확장을 쓰세요.** 하지만 HTMX 본연의 맛은 HTML 조각을 주고받는 데 있음을 기억하면 좋습니다. 다음 시간에는 DRF의 편리함을 [[HTMX]]에 녹여내는 방법으로 돌아오겠습니다! **관련글읽기** - [Django와 HTMX로 동적 웹 개발을 단순화하기 (1편)](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification/) - [Django와 HTMX로 동적 웹 개발을 단순화하기 - Ajax (2편)](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification-2/) - [Django와 HTMX로 동적 웹 개발 단순화하기 (3편): Django 통합 방법](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification-3/) - [Django와 HTMX로 동적 웹 개발을 단순화하기 (5편)](/ko/whitedec/2025/1/27/django-htmx-advanced-features/) - [Django와 HTMX로 동적 웹 개발을 단순화하기 (6편): HTML 반환 방식](/ko/whitedec/2025/1/27/django-htmx-html-response/) - [Django와 HTMX로 동적 웹 개발을 단순화하기 (7편): JSON 반환 방식](/ko/whitedec/2025/1/27/django-htmx-json-response/) - [Django와 HTMX로 동적 웹 개발 단순화: Form과 Serializer 활용법](/ko/whitedec/2026/4/22/django-htmx-forms-serializer-usage/)