htmx × Django / Flask:Python バックエンドとの最適連携

Web 開発の世界で、フロントエンドとバックエンドの境界線が曖昧になる中、Python 開発者にとって革新的な選択肢が登場しました。それがhtmxです。
従来の SPA(Single Page Application)開発では、React や Vue.js といった複雑な JavaScript フレームワークを習得する必要がありました。しかし、htmx を使えば、慣れ親しんだ Django や Flask の知識だけで、モダンで快適な Web アプリケーションを構築できるのです。
この記事では、htmx と Python バックエンドの最適な連携方法について、実際のコード例とともに詳しく解説いたします。Python 開発者の皆さんが、新しい技術の海で迷子にならず、確実にスキルアップできる道筋をご案内させていただきますね。
背景
モダン Web アプリケーション開発の課題
現代の Web 開発において、ユーザーエクスペリエンスの向上は避けて通れない課題となっています。ページを丸ごと再読み込みする従来の Web アプリケーションでは、ユーザーの離脱率が高くなってしまうことが明らかになっていますね。
Google の調査によると、ページの読み込み時間が 1 秒から 3 秒に増加すると、直帰率は 32%も増加するというデータがあります。この事実は、私たち開発者にとって非常に重要な意味を持っているでしょう。
読み込み時間 | 直帰率の増加 | ユーザー体験への影響 |
---|---|---|
1 秒 | ベースライン | 快適 |
3 秒 | +32% | やや遅い |
5 秒 | +90% | ストレスを感じる |
10 秒 | +123% | 離脱を検討 |
SPA vs MPA:選択の分岐点
多くの Python 開発者が直面するのが、SPA(Single Page Application)と MPA(Multi Page Application)の選択です。
SPA の課題:
- React、Vue.js、Angular の学習コストが高い
- JavaScript のビルドツールチェーンの複雑さ
- SEO 対応の困難さ
- 初期表示速度の低下
従来の MPA の課題:
- ページ遷移時の画面の白い点滅
- ユーザーの操作感の途切れ
- 現代的なインタラクティブ機能の実装困難
htmx が注目される理由
htmx は、これらの課題を解決する第三の選択肢として注目を集めています。**「HTML over the wire」**という哲学のもと、サーバーサイドで HTML を生成し、必要な部分だけを動的に更新するアプローチを採用しているのです。
このアプローチの素晴らしさは、Python 開発者が既に持っているスキルセットを最大限活用できる点にあります。新しいフレームワークを一から学ぶ必要がなく、Django や Flask の知識だけでモダンな Web アプリケーションを構築できるのです。
課題
従来の Ajax 実装の複雑さ
従来の Ajax 実装では、以下のような JavaScript コードが必要でした:
javascript// 従来のAjax実装例
function updateUserList() {
fetch('/api/users')
.then((response) => response.json())
.then((data) => {
const userList = document.getElementById('user-list');
userList.innerHTML = '';
data.users.forEach((user) => {
const userElement = document.createElement('div');
userElement.className = 'user-item';
userElement.innerHTML = `
<h3>${user.name}</h3>
<p>${user.email}</p>
<button onclick="deleteUser(${user.id})">削除</button>
`;
userList.appendChild(userElement);
});
})
.catch((error) => {
console.error('Error:', error);
alert('データの取得に失敗しました');
});
}
このコードの問題点は明らかです。DOM 操作、エラーハンドリング、HTML 生成の責務がフロントエンドに分散しており、保守性が低くなってしまいます。
Django/Flask でのフロントエンド連携の難しさ
Django や Flask でモダンなフロントエンドを実装しようとすると、以下のような課題に直面することがよくあります:
1. API エンドポイントの設計負荷
python# Django REST Framework での複雑なAPI設計
from rest_framework import serializers, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
@action(detail=False, methods=['post'])
def bulk_update(self, request):
# 複雑なバルク更新ロジック
users_data = request.data.get('users', [])
errors = []
for user_data in users_data:
try:
user = User.objects.get(id=user_data['id'])
serializer = UserSerializer(user, data=user_data, partial=True)
if serializer.is_valid():
serializer.save()
else:
errors.append(serializer.errors)
except User.DoesNotExist:
errors.append({'id': ['User not found']})
if errors:
return Response({'errors': errors}, status=400)
return Response({'success': True})
2. よく発生する CORS エラー
フロントエンドとバックエンドを分離すると、以下のような CORS エラーが頻繁に発生します:
csharpAccess to fetch at 'http://localhost:8000/api/users' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on
the requested resource.
JavaScript 重要度の高まりと学習コスト
現代の Web 開発では、JavaScript の技術スタックが複雑化しています:
技術要素 | 学習時間目安 | 難易度 |
---|---|---|
ES6+ JavaScript | 40-60 時間 | 中 |
React/Vue.js | 80-120 時間 | 高 |
Webpack/Vite | 30-50 時間 | 中 |
TypeScript | 60-80 時間 | 高 |
状態管理(Redux 等) | 40-60 時間 | 高 |
Python 開発者にとって、これらすべてを習得するのは大きな負担となってしまいますね。
解決策
htmx によるシンプルな HTML 駆動アプローチ
htmx は、HTML 属性を使ってインタラクティブな機能を実装できる画期的なライブラリです。以下の例をご覧ください:
html<!-- htmx による簡潔な実装 -->
<div id="user-list">
<button
hx-get="/users"
hx-target="#user-list"
hx-swap="innerHTML"
>
ユーザー一覧を更新
</button>
</div>
たった 3 つの属性だけで、Ajax 通信と DOM 更新が完了します。この簡潔さこそが、htmx の最大の魅力と言えるでしょう。
htmx の主要な属性一覧:
属性 | 機能 | 使用例 |
---|---|---|
hx-get | GET リクエスト | hx-get="/api/data" |
hx-post | POST リクエスト | hx-post="/api/submit" |
hx-target | 更新対象の指定 | hx-target="#result" |
hx-swap | 更新方法の指定 | hx-swap="outerHTML" |
hx-trigger | トリガーイベント | hx-trigger="keyup delay:500ms" |
Django/Flask との自然な統合方法
Django での統合
Django で htmx を使用する場合、通常のビューをベースに、部分的な HTML テンプレートを返すだけで実装できます:
python# Django views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import User
def user_list(request):
"""ユーザー一覧を返すビュー"""
if request.headers.get('HX-Request'):
# htmx からのリクエストの場合、部分テンプレートを返す
users = User.objects.all()
return render(request, 'partials/user_list.html', {'users': users})
# 通常のページリクエストの場合、完全なページを返す
return render(request, 'users/index.html')
def add_user(request):
"""ユーザー追加処理"""
if request.method == 'POST':
name = request.POST.get('name')
email = request.POST.get('email')
try:
user = User.objects.create(name=name, email=email)
# 成功時は更新されたユーザーリストを返す
users = User.objects.all()
return render(request, 'partials/user_list.html', {'users': users})
except Exception as e:
# エラー時はエラーメッセージを返す
return HttpResponse(f'<div class="error">エラー: {str(e)}</div>', status=400)
Flask での統合
Flask でも同様にシンプルな実装が可能です:
python# Flask app.py
from flask import Flask, request, render_template, jsonify
from models import User, db
app = Flask(__name__)
@app.route('/users')
def user_list():
"""ユーザー一覧を返すルート"""
users = User.query.all()
# htmx からのリクエストかどうかを判定
if request.headers.get('HX-Request'):
return render_template('partials/user_list.html', users=users)
return render_template('users/index.html', users=users)
@app.route('/users', methods=['POST'])
def add_user():
"""ユーザー追加処理"""
try:
name = request.form.get('name')
email = request.form.get('email')
# バリデーション
if not name or not email:
return '<div class="error">名前とメールアドレスは必須です</div>', 400
# ユーザー作成
user = User(name=name, email=email)
db.session.add(user)
db.session.commit()
# 更新されたリストを返す
users = User.query.all()
return render_template('partials/user_list.html', users=users)
except Exception as e:
return f'<div class="error">エラーが発生しました: {str(e)}</div>', 500
レスポンシブでインタラクティブな UI 実現
htmx を使用することで、以下のような高度なインタラクション機能を簡単に実装できます:
リアルタイム検索機能
html<!-- 検索フォーム -->
<input
type="text"
name="search"
hx-get="/search"
hx-trigger="keyup changed delay:300ms"
hx-target="#search-results"
placeholder="ユーザーを検索..."
/>
<div id="search-results">
<!-- 検索結果がここに表示される -->
</div>
対応する Python コード:
python# Django での検索実装
def search_users(request):
query = request.GET.get('search', '')
if query:
users = User.objects.filter(
Q(name__icontains=query) | Q(email__icontains=query)
)
else:
users = User.objects.all()
return render(request, 'partials/user_search_results.html', {
'users': users,
'query': query
})
具体例
Django での htmx 導入実装
ここからは、実際に Django プロジェクトで htmx を導入する手順を詳しく解説いたします。
1. プロジェクトのセットアップ
まず、新しい Django プロジェクトを作成しましょう:
bash# 仮想環境の作成と有効化
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Django のインストール
pip install django
pip install django-htmx # htmx 用のDjangoパッケージ
# プロジェクトの作成
django-admin startproject htmx_demo
cd htmx_demo
python manage.py startapp users
2. 設定ファイルの更新
python# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_htmx', # htmx サポートを追加
'users',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django_htmx.middleware.HtmxMiddleware', # htmx ミドルウェア
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
3. モデルの定義
python# users/models.py
from django.db import models
from django.core.validators import EmailValidator
class User(models.Model):
name = models.CharField(max_length=100, verbose_name='名前')
email = models.EmailField(
validators=[EmailValidator()],
unique=True,
verbose_name='メールアドレス'
)
created_at = models.DateTimeField(auto_now_add=True, verbose_name='作成日時')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新日時')
class Meta:
verbose_name = 'ユーザー'
verbose_name_plural = 'ユーザー'
ordering = ['-created_at']
def __str__(self):
return self.name
4. ビューの実装
python# users/views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from django.contrib import messages
from django.db import IntegrityError
from .models import User
import logging
logger = logging.getLogger(__name__)
def user_list(request):
"""ユーザー一覧ページ"""
users = User.objects.all()
if request.htmx:
return render(request, 'users/partials/user_list.html', {'users': users})
return render(request, 'users/index.html', {'users': users})
def add_user(request):
"""ユーザー追加処理"""
if request.method == 'POST':
name = request.POST.get('name', '').strip()
email = request.POST.get('email', '').strip()
# バリデーション
if not name or not email:
error_msg = '<div class="alert alert-danger">名前とメールアドレスは必須項目です</div>'
return HttpResponse(error_msg, status=400)
try:
user = User.objects.create(name=name, email=email)
logger.info(f'新しいユーザーが作成されました: {user.name} ({user.email})')
# 成功時は更新されたユーザーリストを返す
users = User.objects.all()
return render(request, 'users/partials/user_list.html', {'users': users})
except IntegrityError:
error_msg = '<div class="alert alert-danger">このメールアドレスは既に使用されています</div>'
return HttpResponse(error_msg, status=400)
except Exception as e:
logger.error(f'ユーザー作成エラー: {str(e)}')
error_msg = '<div class="alert alert-danger">予期しないエラーが発生しました</div>'
return HttpResponse(error_msg, status=500)
return HttpResponse(status=405) # Method Not Allowed
5. テンプレートの作成
メインテンプレート:
html<!-- users/templates/users/index.html -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>htmx × Django デモ</title>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
</head>
<body>
<div class="container mt-5">
<h1 class="mb-4">ユーザー管理システム</h1>
<!-- ユーザー追加フォーム -->
<div class="card mb-4">
<div class="card-header">
<h5>新規ユーザー追加</h5>
</div>
<div class="card-body">
<form
hx-post="{% url 'add_user' %}"
hx-target="#user-list"
hx-swap="outerHTML"
>
{% csrf_token %}
<div class="row">
<div class="col-md-4">
<input
type="text"
name="name"
class="form-control"
placeholder="名前"
required
/>
</div>
<div class="col-md-4">
<input
type="email"
name="email"
class="form-control"
placeholder="メールアドレス"
required
/>
</div>
<div class="col-md-4">
<button
type="submit"
class="btn btn-primary"
>
追加
</button>
</div>
</div>
</form>
</div>
</div>
<!-- エラーメッセージ表示エリア -->
<div id="error-messages"></div>
<!-- ユーザーリスト -->
<div id="user-list">
{% include 'users/partials/user_list.html' %}
</div>
</div>
</body>
</html>
部分テンプレート:
html<!-- users/templates/users/partials/user_list.html -->
<div class="card">
<div
class="card-header d-flex justify-content-between align-items-center"
>
<h5>ユーザー一覧</h5>
<span class="badge bg-primary"
>{{ users.count }}人</span
>
</div>
<div class="card-body">
{% if users %}
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>名前</th>
<th>メールアドレス</th>
<th>作成日時</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.created_at|date:"Y/m/d H:i" }}</td>
<td>
<button
class="btn btn-sm btn-danger"
hx-delete="{% url 'delete_user' user.id %}"
hx-target="#user-list"
hx-swap="outerHTML"
hx-confirm="本当に削除しますか?"
>
削除
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-muted">ユーザーが登録されていません。</p>
{% endif %}
</div>
</div>
Flask での htmx 活用パターン
Flask でも同様に強力な htmx アプリケーションを構築できます。ここでは、よくある課題とその解決方法を見ていきましょう。
1. Flask アプリケーションの基本構造
python# app.py
from flask import Flask, request, render_template, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, EmailField, SubmitField
from wtforms.validators import DataRequired, Email
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# ユーザーモデル
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def __repr__(self):
return f'<User {self.name}>'
# フォームクラス
class UserForm(FlaskForm):
name = StringField('名前', validators=[DataRequired()])
email = EmailField('メールアドレス', validators=[DataRequired(), Email()])
submit = SubmitField('追加')
2. htmx 対応のルート実装
python@app.route('/')
def index():
"""メインページ"""
users = User.query.all()
form = UserForm()
return render_template('index.html', users=users, form=form)
@app.route('/users', methods=['GET'])
def get_users():
"""ユーザー一覧取得(htmx用)"""
users = User.query.all()
return render_template('partials/user_list.html', users=users)
@app.route('/users', methods=['POST'])
def add_user():
"""ユーザー追加処理"""
form = UserForm()
if form.validate_on_submit():
try:
user = User(name=form.name.data, email=form.email.data)
db.session.add(user)
db.session.commit()
# 成功時は更新されたユーザーリストを返す
users = User.query.all()
return render_template('partials/user_list.html', users=users)
except Exception as e:
# データベースエラーの処理
db.session.rollback()
if 'UNIQUE constraint failed' in str(e):
error_msg = 'このメールアドレスは既に使用されています。'
else:
error_msg = f'データベースエラーが発生しました: {str(e)}'
return f'<div class="alert alert-danger">{error_msg}</div>', 400
# バリデーションエラーの場合
errors = []
for field, error_list in form.errors.items():
for error in error_list:
errors.append(f'{form[field].label.text}: {error}')
error_msg = '<br>'.join(errors)
return f'<div class="alert alert-danger">{error_msg}</div>', 400
3. エラーハンドリングとレスポンス形式
Flask では、htmx 用のエラーレスポンスを適切に処理することが重要です:
python@app.errorhandler(404)
def not_found_error(error):
"""404エラーハンドラ"""
if request.headers.get('HX-Request'):
return '<div class="alert alert-warning">要求されたリソースが見つかりません。</div>', 404
return render_template('errors/404.html'), 404
@app.errorhandler(500)
def internal_error(error):
"""500エラーハンドラ"""
db.session.rollback()
if request.headers.get('HX-Request'):
return '<div class="alert alert-danger">内部エラーが発生しました。</div>', 500
return render_template('errors/500.html'), 500
# CSRF保護のためのカスタムヘルパー
@app.template_global()
def is_htmx_request():
"""テンプレート内でhtmxリクエストかどうかを判定"""
return request.headers.get('HX-Request') == 'true'
リアルタイム更新とフォーム処理
htmx の真の力は、リアルタイム更新とスムーズなフォーム処理にあります。ここでは、実用的な機能を実装してみましょう。
1. 自動保存機能の実装
ユーザーがフォームに入力している途中で、自動的に下書きを保存する機能を実装します:
html<!-- 自動保存フォーム -->
<form id="draft-form">
{% csrf_token %}
<div class="mb-3">
<label for="title" class="form-label">タイトル</label>
<input
type="text"
name="title"
id="title"
class="form-control"
hx-post="{% url 'save_draft' %}"
hx-trigger="keyup changed delay:1000ms"
hx-target="#save-status"
hx-include="#draft-form"
/>
</div>
<div class="mb-3">
<label for="content" class="form-label">内容</label>
<textarea
name="content"
id="content"
class="form-control"
rows="10"
hx-post="{% url 'save_draft' %}"
hx-trigger="keyup changed delay:1000ms"
hx-target="#save-status"
hx-include="#draft-form"
></textarea>
</div>
<div id="save-status" class="text-muted">
<!-- 保存ステータスがここに表示される -->
</div>
</form>
対応する Django ビュー:
pythonfrom django.utils import timezone
import json
def save_draft(request):
"""下書き自動保存"""
if request.method == 'POST':
title = request.POST.get('title', '')
content = request.POST.get('content', '')
# セッションに下書きを保存
request.session['draft'] = {
'title': title,
'content': content,
'saved_at': timezone.now().isoformat()
}
# 保存成功のメッセージを返す
saved_time = timezone.now().strftime('%H:%M:%S')
return HttpResponse(f'<small class="text-success">✓ {saved_time} に自動保存されました</small>')
return HttpResponse('<small class="text-danger">保存に失敗しました</small>', status=400)
2. 無限スクロール機能
大量のデータを効率的に表示するために、無限スクロール機能を実装しましょう:
python# Django でのページネーション実装
from django.core.paginator import Paginator
from django.db.models import Q
def infinite_scroll_users(request):
"""無限スクロール用のユーザー取得"""
page = int(request.GET.get('page', 1))
search = request.GET.get('search', '')
# 検索クエリの適用
users = User.objects.all()
if search:
users = users.filter(
Q(name__icontains=search) | Q(email__icontains=search)
)
# ページネーション
paginator = Paginator(users, 10) # 1ページ10件
page_obj = paginator.get_page(page)
# htmx リクエストの場合は部分テンプレートを返す
if request.htmx:
return render(request, 'partials/user_page.html', {
'page_obj': page_obj,
'search': search
})
# 初回リクエストの場合は全体ページを返す
return render(request, 'users/infinite_scroll.html', {
'page_obj': page_obj,
'search': search
})
対応するテンプレート:
html<!-- partials/user_page.html -->
{% for user in page_obj %}
<div class="card mb-2">
<div class="card-body">
<h6 class="card-title">{{ user.name }}</h6>
<p class="card-text">{{ user.email }}</p>
<small class="text-muted"
>{{ user.created_at|date:"Y/m/d" }}</small
>
</div>
</div>
{% endfor %} {% if page_obj.has_next %}
<div
hx-get="{% url 'infinite_scroll_users' %}?page={{ page_obj.next_page_number }}&search={{ search }}"
hx-target="this"
hx-swap="outerHTML"
hx-trigger="revealed"
>
<div class="text-center p-3">
<div class="spinner-border" role="status">
<span class="visually-hidden">読み込み中...</span>
</div>
</div>
</div>
{% endif %}
3. よくあるエラーとその解決方法
実際の開発では、以下のようなエラーに遭遇することがあります:
CSRF トークンエラー:
scssForbidden (403)
CSRF verification failed. Request aborted.
解決方法:
html<!-- CSRFトークンを含むフォーム -->
<form hx-post="{% url 'your_view' %}">
{% csrf_token %}
<!-- フォームフィールド -->
</form>
<!-- または、メタタグとJavaScriptを使用 -->
<meta name="csrf-token" content="{{ csrf_token }}" />
<script>
document.addEventListener(
'htmx:configRequest',
function (event) {
event.detail.headers['X-CSRFToken'] =
document.querySelector(
'meta[name="csrf-token"]'
).content;
}
);
</script>
404 Not Found エラー:
csharpNot Found: /users/update/
The requested resource was not found on this server.
URL パターンの確認と修正:
python# urls.py での正しいパターン定義
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('users/', views.user_list, name='user_list'),
path('users/add/', views.add_user, name='add_user'),
path('users/<int:user_id>/update/', views.update_user, name='update_user'),
path('users/<int:user_id>/delete/', views.delete_user, name='delete_user'),
]
まとめ
この記事を通じて、htmx と Python バックエンド(Django/Flask)の組み合わせがいかに強力で実用的かということをお伝えできたのではないでしょうか。
htmx × Python の主要なメリット:
メリット | 従来の方法 | htmx 使用時 |
---|---|---|
学習コスト | JavaScript 重要、複雑なフレームワーク | HTML 属性のみ |
開発速度 | フロント/バック分離で複雑 | サーバーサイドで完結 |
保守性 | 状態管理が複雑 | シンプルな HTML 構造 |
SEO 対応 | 別途対策が必要 | 自然に SEO フレンドリー |
チーム体制 | フロントエンド専門家が必要 | Python エンジニアで完結 |
重要なポイント:
- htmx は既存の Python スキルを最大限活用できる技術です
- 段階的な導入が可能で、既存のプロジェクトにも適用できます
- JavaScript フレームワークの複雑さから解放され、本質的な機能開発に集中できます
- サーバーサイドで HTML を生成するため、SEO やアクセシビリティの面でも優れています
Python 開発者の皆さんが、新しい技術に対する不安を感じることなく、確実にモダンな Web アプリケーションを構築できることを願っています。htmx という新しい選択肢を手に入れることで、より効率的で楽しい開発体験を得られることでしょう。
技術の進歩は速いものですが、基本的なプログラミングスキルと HTML/CSS の知識があれば、htmx は確実に皆さんの開発力を向上させてくれるはずです。ぜひ一度、実際のプロジェクトで試してみてくださいね。
関連リンク
公式ドキュメント
- htmx 公式サイト - htmx の公式ドキュメントとチュートリアル
- Django 公式ドキュメント - Django の日本語公式ドキュメント
- Flask 公式ドキュメント - Flask の公式ドキュメント
Django 関連パッケージ
- django-htmx - Django で htmx をサポートするパッケージ
- Django REST Framework - Django で API を構築するためのフレームワーク
Flask 関連パッケージ
- Flask-WTF - Flask で WTForms を使用するための拡張
- Flask-SQLAlchemy - Flask で SQLAlchemy を使用するための拡張
学習リソース
- htmx Examples - htmx の実用的な使用例集
- Real Python - Python 学習のための高品質なコンテンツ
- Mozilla Developer Network - Web 技術の包括的なドキュメント
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来