Django 5.0 su HTMX: mažiau JavaScript

Kodėl vis dar rašome tiek daug JavaScript kodo?

Kiekvienas web programuotojas žino tą jausmą – pradedi kurti paprastą formą su dinaminiu turiniu, o po kelių valandų jau turi 500 eilučių JavaScript kodo, kuris tvarko DOM manipuliavimą, fetch užklausas, klaidų apdorojimą ir dar dešimt kitų dalykų. Ir tada pagalvoji: „Ar tikrai turėjo būti taip sudėtinga?”

Django 5.0 kartu su HTMX siūlo visiškai kitokį požiūrį. Vietoj to, kad kurtumėte sudėtingą frontend logiką su React, Vue ar Angular, galite pasiekti panašų interaktyvumą su minimaliu JavaScript kodu. Skamba per gerai, kad būtų tiesa? Pažiūrėkime, kaip tai veikia praktikoje.

HTMX filosofija paprasta – serveris grąžina HTML fragmentus, o ne JSON duomenis. Tai reiškia, kad visa logika lieka ten, kur Django programuotojams patogiausia – Python pusėje. Jokių sudėtingų state management bibliotekų, jokio duomenų serializavimo pirmyn ir atgal, jokių nesuderinamų API versijų.

Kas yra HTMX ir kaip jis veikia su Django

HTMX yra nedidelė JavaScript biblioteka (apie 14KB suglaudinta), leidžianti bet kuriam HTML elementui siųsti AJAX užklausas ir atnaujinti puslapio dalį su serverio atsakymu. Skirtingai nuo tradicinių SPA frameworkų, čia nereikia rašyti JavaScript kodo – viskas valdoma per HTML atributus.

Paprasta HTMX forma Django projekte atrodo maždaug taip:

„`html

{% csrf_token %}


{% for task in tasks %}

{{ task.title }}

{% endfor %}

„`

Kai vartotojas paspaudžia „Pridėti”, HTMX automatiškai:
– Siunčia POST užklausą į `/tasks/create/`
– Gauna HTML atsakymą iš serverio
– Įterpia jį į `#task-list` elemento pradžią
– Visa tai be puslapio perkrovimo

Django view’as gali būti paprastas kaip:

„`python
def create_task(request):
if request.method == ‘POST’:
title = request.POST.get(‘title’)
task = Task.objects.create(title=title)
return render(request, ‘partials/task_item.html’, {‘task’: task})
„`

Jokio JSON, jokio `JsonResponse`, jokių sudėtingų serializatorių. Tiesiog grąžinate HTML fragmentą.

Django 5.0 naujienos, kurios puikiai dera su HTMX

Django 5.0 versija atsirado 2023 metų gruodį ir atnešė keletą pakeitimų, kurie daro HTMX integraciją dar sklandesnę. Vienas svarbiausių – pagerintas šablonų sistemos našumas ir nauja `{% query_string %}` template tag, kuri puikiai tinka dinaminiams filtrams kurti.

Pavyzdžiui, jei kuriate produktų sąrašą su filtrais:

„`html

„`

Django 5.0 taip pat įvedė geresnes asinchronines galimybes. Nors HTMX pats savaime nėra async, galite naudoti Django async views, kad pagreitintumėte atsakymo laiką, ypač kai reikia daryti kelias duomenų bazės užklausas:

„`python
async def get_dashboard_data(request):
tasks = await Task.objects.filter(user=request.user).aall()
notifications = await Notification.objects.filter(user=request.user).aall()

return render(request, ‘partials/dashboard.html’, {
‘tasks’: tasks,
‘notifications’: notifications
})
„`

Dar viena naujovė – pagerintas `Field.choices` valdymas, kuris palengvina dinamiškų formų kūrimą. Kai naudojate HTMX formoms, galite lengvai atnaujinti select laukus priklausomai nuo kitų pasirinkimų.

Praktiniai pavyzdžiai: kas veikia puikiai

Pabandžius HTMX su Django realuose projektuose, kai kurie dalykai veikia tiesiog nuostabiai. Infinite scroll yra vienas iš jų. Tradiciškai tam reikėtų nemažai JavaScript kodo, bet su HTMX:

„`html

{% for item in items %}

{{ item.title }}

{% endfor %}

{% if has_next %}

Kraunama…

{% endif %}
„`

Atributas `hx-trigger=”revealed”` reiškia, kad užklausa bus išsiųsta, kai elementas pasirodys ekrane. Viskas.

Modaliniai langai – dar vienas dalykas, kuris tampa trivialus. Nereikia jokių JavaScript bibliotekų:

„`html

„`

Serveris grąžina pilną modalinio lango HTML su forma, o HTMX jį tiesiog įterpia. Forma gali būti apdorojama su tuo pačiu HTMX, grąžinant arba atnaujintą turinį, arba klaidas.

Realaus laiko paieška taip pat tampa paprasta. Štai kaip galite implementuoti live search su debouncing:

„`html

„`

`delay:500ms` užtikrina, kad užklausa bus išsiųsta tik tada, kai vartotojas nustoja rašyti 500ms. Nereikia rašyti debounce funkcijos JavaScript’e.

Kur gali kilti problemų

Nors HTMX atrodo kaip stebuklas, ne viskas yra rožėmis klotas. Viena didžiausių problemų – trečiųjų šalių JavaScript bibliotekų integracija. Jei naudojate kokį nors fancy datepicker ar rich text editor, gali tekti papildomai padirbėti, kad jie veiktų su dinaminiu turiniu.

Problema ta, kad kai HTMX įterpia naują HTML, JavaScript bibliotekos, kurios buvo inicializuotos puslapio užkrovimo metu, nežino apie naujus elementus. Sprendimas – naudoti HTMX events:

„`javascript
document.body.addEventListener(‘htmx:afterSwap’, function(evt) {
// Reinicializuoti datepickers naujuose elementuose
flatpickr(evt.detail.target.querySelectorAll(‘.datepicker’));
});
„`

Taip, tai JavaScript kodas, bet jo reikia tik vieną kartą parašyti, o ne kiekvienai interakcijai.

Kita problema – SEO. Jei jūsų turinys yra užkraunamas per HTMX, paieškos robotai jo nematys. Sprendimas – užtikrinti, kad pirminis puslapio užkrovimas grąžina visą svarbų turinį, o HTMX naudojamas tik papildomam interaktyvumui. Arba naudoti server-side rendering su progressive enhancement principu.

Dar vienas dalykas – debugging. Kai viskas vyksta per HTML atributus, kartais sunku suprasti, kodėl kažkas neveikia. Django Debug Toolbar padeda, bet vis tiek gali tekti pasikasti HTMX dokumentacijoje. Patarimas – įjunkite HTMX debug režimą development aplinkoje:

„`html

„`

Formos ir validacija: kaip daryti teisingai

Formos su HTMX reikalauja šiek tiek kitokio mąstymo. Tradiciškai Django forma, kuri turi klaidų, perkrauna puslapį ir rodo klaidas. Su HTMX norite grąžinti tik formos HTML su klaidomis, neliesdami likusio puslapio.

Štai kaip galite organizuoti view’ą:

„`python
def create_article(request):
if request.method == ‘POST’:
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save()
# Grąžiname success pranešimą ir naują straipsnį
return render(request, ‘partials/article_created.html’, {
‘article’: article
})
else:
# Grąžiname formą su klaidomis
return render(request, ‘partials/article_form.html’, {
‘form’: form
}, status=400)

form = ArticleForm()
return render(request, ‘partials/article_form.html’, {‘form’: form})
„`

Svarbu grąžinti 400 status kodą, kai forma turi klaidų – tai leidžia HTMX žinoti, kad kažkas nepavyko. Galite naudoti `hx-target-error` atributą, kad nurodytumėte, kur rodyti klaidas:

„`html



„`

Dar geresnis variantas – naudoti Django messages framework kartu su HTMX. Galite sukurti partial template’ą pranešimams:

„`html

{% if messages %}

{% for message in messages %}

{{ message }}

{% endfor %}

{% endif %}
„`

`hx-swap-oob=”true”` (out of band swap) reiškia, kad šis elementas bus atnaujintas nepriklausomai nuo pagrindinio target. Tai leidžia grąžinti ir formos rezultatą, ir pranešimus tuo pačiu metu.

Optimizavimas ir našumas

Vienas iš HTMX privalumų – mažesnis duomenų kiekis tinkle, nes nereikia siųsti JavaScript bundle’ų. Bet tai nereiškia, kad nereikia galvoti apie našumą. Serveris dabar atlieka daugiau darbo – generuoja HTML vietoj JSON.

Pirmiausia – caching. Django template fragmentų cache’inimas tampa dar svarbesnis:

„`python
from django.views.decorators.cache import cache_page

@cache_page(60 * 5) # 5 minutės
def get_popular_articles(request):
articles = Article.objects.filter(published=True).order_by(‘-views’)[:10]
return render(request, ‘partials/popular_articles.html’, {
‘articles’: articles
})
„`

Arba naudokite template cache tag:

„`html
{% load cache %}
{% cache 500 sidebar request.user.username %}

{% endcache %}
„`

Antra – optimizuokite duomenų bazės užklausas. Kadangi dabar grąžinate HTML fragmentus, lengva pamiršti apie N+1 problemas. Naudokite `select_related()` ir `prefetch_related()`:

„`python
def get_comments(request, article_id):
comments = Comment.objects.filter(
article_id=article_id
).select_related(‘author’).prefetch_related(‘likes’)

return render(request, ‘partials/comments.html’, {
‘comments’: comments
})
„`

Trečia – lazy loading. HTMX puikiai tinka turiniui, kuris nėra iškart matomas. Pavyzdžiui, komentarai gali būti užkraunami tik tada, kai vartotojas nuslenka žemyn:

„`html

Kraunami komentarai…

„`

Tai sumažina pradinį puslapio užkrovimo laiką ir duomenų bazės apkrovą.

Testavimas: kaip įsitikinti, kad viskas veikia

Testavimas su HTMX gali būti paprastesnis nei su SPA, nes visa logika yra serveryje. Galite naudoti standartinį Django test client:

„`python
from django.test import TestCase

class TaskViewTests(TestCase):
def test_create_task_htmx(self):
response = self.client.post(‘/tasks/create/’, {
‘title’: ‘Test task’
}, HTTP_HX_REQUEST=’true’)

self.assertEqual(response.status_code, 200)
self.assertContains(response, ‘Test task’)
self.assertTemplateUsed(response, ‘partials/task_item.html’)
„`

`HTTP_HX_REQUEST=’true’` header’is simuliuoja HTMX užklausą. Galite tikrinti, ar view’as grąžina teisingą template’ą ir turinį.

Jei norite testuoti pilną vartotojo patirtį su HTMX, galite naudoti Playwright ar Selenium:

„`python
from playwright.sync_api import sync_playwright

def test_task_creation_e2e():
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto(‘http://localhost:8000/tasks/’)

page.fill(‘input[name=”title”]’, ‘New task’)
page.click(‘button[type=”submit”]’)

# Laukti, kol HTMX atnaujins turinį
page.wait_for_selector(‘.task:has-text(„New task”)’)

assert page.locator(‘.task’).count() > 0
browser.close()
„`

Vienas iš HTMX privalumų testavime – galite testuoti daugumą funkcionalumo su paprastais unit testais, o end-to-end testus naudoti tik kritinėms user flow.

Kada HTMX nėra geriausias pasirinkimas

Būkime sąžiningi – HTMX nėra sidabrinis kulka. Yra situacijų, kai tradicinis SPA framework’as būtų geresnis pasirinkimas.

Real-time aplikacijos su WebSocket’ais. Nors HTMX palaiko WebSocket’us, jei kuriate chat aplikaciją ar collaborative editing tool, React su Socket.io ar Vue su Pusher gali būti patogesnė.

Sudėtingos single-page aplikacijos su daug kliento pusės logikos. Jei jūsų aplikacija turi sudėtingą state management, daug tarpusavyje susijusių komponentų ir reikalauja offline funkcionalumo, HTMX gali tapti apribojančiu veiksniu.

Mobilios aplikacijos. Jei planuojate kurti native mobile app su React Native ar Flutter, turėti bendrą API backend’ą su JSON gali būti praktiškai. Nors galite naudoti HTMX ir mobile webview, tai ne idealu.

Labai interaktyvūs UI komponentai. Jei kuriate kažką panašaus į Google Sheets ar Figma, kur kiekvienas pelės judesys turi būti apdorotas, HTMX nesugebės to efektyviai padaryti.

Bet daugumai CRUD aplikacijų, admin panel’ių, content management sistemų, e-commerce platformų – HTMX su Django yra puikus pasirinkimas. Jūs gaunate 80% SPA funkcionalumo su 20% sudėtingumo.

Kaip pradėti: žingsnis po žingsnio

Jei įtikinau jus pabandyti HTMX su Django 5.0, štai kaip pradėti. Pirma, įsitikinkite, kad turite Django 5.0 ar naujesnę versiją:

„`bash
pip install Django>=5.0
„`

Sukurkite naują projektą arba naudokite esamą. Įtraukite HTMX į savo base template’ą:

„`html




{% block title %}Mano projektas{% endblock %}



{% block content %}{% endblock %}


„`

Production aplinkoje geriau atsisiųsti HTMX failą ir servinti jį su Django static files.

Sukurkite paprastą view’ą, kuris grąžina HTML fragmentą:

„`python
# views.py
from django.shortcuts import render
from django.views.decorators.http import require_http_methods

@require_http_methods([„GET”, „POST”])
def task_list(request):
if request.method == „POST”:
title = request.POST.get(„title”)
Task.objects.create(title=title, user=request.user)
tasks = Task.objects.filter(user=request.user)
return render(request, „partials/task_list.html”, {„tasks”: tasks})

tasks = Task.objects.filter(user=request.user)
return render(request, „tasks.html”, {„tasks”: tasks})
„`

Sukurkite template’us:

„`html

{% extends „base.html” %}

{% block content %}

Mano užduotys


{% csrf_token %}


{% include „partials/task_list.html” %}

{% endblock %}
„`

„`html

{% for task in tasks %}

{{ task.title }}

{% endfor %}
„`

Ir viskas! Turite veikiančią interaktyvią aplikaciją be JavaScript kodo.

Rekomenduoju pradėti nuo mažų dalykų – pakeiskite vieną formą ar vieną sąrašą į HTMX. Pamatysite, kaip tai veikia, ir galėsite palaipsniui plėsti. Nereikia perrašyti viso projekto iš karto.

Ką veikti toliau: ištekliai ir bendruomenė

HTMX bendruomenė auga labai sparčiai. Oficiali dokumentacija (htmx.org) yra puiki – aiški, su daugybe pavyzdžių. Yra ir Discord serveris, kur galite užduoti klausimus.

Django pusėje, django-htmx paketas (https://github.com/adamchainz/django-htmx) prideda naudingų middleware ir helper funkcijų. Pavyzdžiui, galite lengvai patikrinti, ar užklausa atėjo iš HTMX:

„`python
def my_view(request):
if request.htmx:
# Grąžinti tik fragmentą
return render(request, ‘partials/content.html’)
else:
# Grąžinti pilną puslapį
return render(request, ‘full_page.html’)
„`

Kiti naudingi ištekliai:
– „Hypermedia Systems” knyga (hypermedia.systems) – gilus įžvalgas į HTMX filosofiją
– Django + HTMX pavyzdžiai GitHub’e – realūs projektai, iš kurių galite mokytis
– YouTube kanalas „BugBytes” turi puikių Django + HTMX tutorial’ų

Ir nepamirškite – HTMX nėra „viskas arba nieko” sprendimas. Galite jį naudoti kartu su Vue ar React komponentais, kai tai prasminga. Pavyzdžiui, galite turėti HTMX pagrindiniams dalykams, o sudėtingesniam UI komponentui naudoti React. Jie puikiai sugyvena.

Svarbiausia – eksperimentuokite. Pabandykite HTMX šoniniam projektui ar vienai funkcijai darbo projekte. Pamatysite, kad daugeliu atvejų tai yra paprastesnis ir greičiau veikiantis sprendimas nei pilnavertis SPA. O Django 5.0 su savo patobulinimais daro šią kombinaciją dar stipresnę.

Galbūt HTMX su Django nėra naujausia ir šauniausia technologija, apie kurią visi kalba konferencijose. Bet kartais senoji gera HTML su šiuolaikiniais patobulinimais yra būtent tai, ko reikia jūsų projektui. Mažiau JavaScript, daugiau produktyvumo – skamba kaip geras sandoris.

Daugiau

Nginx konfigūracija Ubuntu 22.04 serveryje