乙Py先生のプログラミング教室

乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

今回は
FastAPI × htmx で作るプロトタイプを爆速実装する方法
についてです。


解説動画はこちら




 FastAPI × htmx

昨今のPython界隈は streamlit というライブラリのおかげで
フロントエンドもまとめて作ることができる様になりました。

そのおかげで、似たような見た目ばかりになる
streamlit臭のするデザインのモックばかり
という哀しい現象が起きてきています。

なので、こんな状況を打破すべく
 - デザイン部分は自由に作り込める
 - フロントエンド(React/Vue)の学習コストが高すぎて、モック作りが進まない
 - FastAPI(堅牢なバックエンド) + htmx(HTML だけで Ajax)というシンプル構成

という FastAPI + htmx の組み合わせの方法をお伝えします。


FastAPI とは何か

爆速で動く、現代的な『注文受け付け窓口』
Python言語で作られたWEBフレームワークです。

プログラムの実行速度が非常に速く
開発者がコードを書くスピードも速くなるように設計されており

仕様書(APIドキュメント)を自動で作成
型(データ)のチェックなども行ってくれます。


htmx とは何か

HTMLを『魔法の言葉』に変える道具
通常、Webページの一部を書き換えるには
JavaScriptをたくさん書く必要があります。

htmxだと「HTMLを数文字書き足すだけ」で実現でき
JavaScriptの部分をHTMLの属性だけで指示できるます。

学習コストが劇的に低い(HTMLが分かるなら)
ので初学者でも取り組みが楽です。


なので
この組み合わせが事業モックに最適です。

フロントとバックエンド、2つの学習コストが低い
シンプルでサクサク動くし、修正が簡単

モックとして作った後も
そのまま本番サービス転用も可能です。



環境構築と基本設定

Python側のインストール
pip install fastapi uvicorn jinja2 python-multipart


FASTAPIの実行方法
main.py のあるディレクトリで
uvicorn main:app --reload

WEBブラウザー側で http://127.0.0.1:8000/
にアクセスするとFASTAPIの画面が見れます。



デモプロジェクトの概要


デモプロジェクトのディレクトリ構成

├── main.py
└── templates/
    ├── index.html        (ベースレイアウト)
    ├── customer_list.html (顧客一覧)
    ├── customer_detail.html (顧客詳細)
    ├── stock_list.html    (在庫一覧)
    ├── stock_detail.html  (在庫詳細)
    └── chat.html          (AIチャット)


こんな内容のものを作ることができます。
スクリーンショット 2026-02-21 17.28.21
スクリーンショット 2026-02-21 17.28.28
スクリーンショット 2026-02-21 17.28.34




main.py のコード

FAST API のコードはこんな感じになっています。
from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from datetime import datetime

app = FastAPI()
templates = Jinja2Templates(directory="templates")

# --- ダミーデータ ---
CUSTOMERS = {
    "C001": {"id": "C001", "name": "山田 太郎", "birth": "1985/05/20", "gender": "男性", "address": "東京都渋谷区...", "rank": "S", "items": [{"name": "ルンバ", "qty": 1, "price": 50000}]},
    "C002": {"id": "C002", "name": "佐藤 花子", "birth": "1992/11/02", "gender": "女性", "address": "大阪府大阪市...", "rank": "A", "items": [{"name": "化粧水", "qty": 2, "price": 4000}]},
    # ...他3件(実装上は同様に定義)
}

STOCKS = {
    "S001": {"id": "S001", "name": "ロキソニンS", "category": "解熱鎮痛剤", "count": 150, "desc": "第1類医薬品。速効性に優れています。"},
    "S002": {"id": "S002", "name": "アレグラFX", "category": "鼻炎薬", "count": 45, "desc": "眠くなりにくいアレルギー専用鼻炎薬。"},
}

def calc_age(birth_str):
    birth_date = datetime.strptime(birth_str, "%Y/%m/%d")
    today = datetime.today()
    return today.year - birth_date.year - ((today.month, today.day) < (birth_date.month, birth_date.day))

# --- Routes ---
@app.get("/", response_class=HTMLResponse)
async def index(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

# 1. 顧客管理
@app.get("/customers", response_class=HTMLResponse)
async def list_customers(request: Request):
    data = []
    for c in CUSTOMERS.values():
        data.append({**c, "age": calc_age(c['birth']), "birth_month": c['birth'][:7]})
    return templates.TemplateResponse("customer_list.html", {"request": request, "customers": data})

@app.get("/customers/{cid}", response_class=HTMLResponse)
async def detail_customer(request: Request, cid: str):
    c = CUSTOMERS.get(cid)
    return templates.TemplateResponse("customer_detail.html", {"request": request, "customer": c, "age": calc_age(c['birth'])})

# 2. 在庫チェック
@app.get("/stocks", response_class=HTMLResponse)
async def list_stocks(request: Request):
    return templates.TemplateResponse("stock_list.html", {"request": request, "stocks": STOCKS.values()})

@app.get("/stocks/{sid}", response_class=HTMLResponse)
async def detail_stock(request: Request, sid: str):
    return templates.TemplateResponse("stock_detail.html", {"request": request, "stock": STOCKS.get(sid)})

# 3. AIチャット
@app.get("/chat", response_class=HTMLResponse)
async def chat_page(request: Request):
    return templates.TemplateResponse("chat.html", {"request": request})

@app.post("/chat/send", response_class=HTMLResponse)
async def chat_send(request: Request, message: str = Form(...)):
    # 簡易的なAIレスポンスのシミュレーション
    ai_response = f"「{message}」について承知いたしました。AIとしての回答をここに表示します。"
    return f"""ここは省略しています"""

index.htmlなどは
AIエージェントを使って作ってみてください





まとめ


FAST API + htmx を用いると爆速でモック開発ができる
こちらは必要最低限の知識を学ぶだけで済む
デザイン部分は自由に作り込めるので好きなCSSを勉強しよう

足りない部分はAIエージェント使ってください
こちらは作りたいものを指示するだけ
本番作りもAIエージェントで爆速開発できます

PS
最近はこれでプロトタイプ開発していたりします。
AIエージェントも使いこなせると
爆速で開発できる様にできますよ

それでは。

 

今回はバイブコーディングを
うまく行かせるためのコツについてです。

解説動画はこちら




バイブコーディングのコツ


昨今ではもう当たり前になってきている
バイブコーディング

これをうまく活かせるための
コツについてお伝えします。


ポイントは3つだけ

1.マークダウン形式で指示する

2.ロールを与える

3.できるだけ具体的に指示する

これだけ守れたら十分です

それ以外の説明や細かい所は
動画の方を見ていただければと思います。



ゲーム作成プロンプト

この内容に、追加で仕様を加えるなどで
改変することができると思います。
# 依頼:HTML Canvasを使用した「掘削アクションパズル」の作成

以下の仕様に基づき、シングルファイルのHTML(HTML/CSS/JS一体型)でゲームを作成してください。

## 1. ゲーム概要
- タイトル:簡易版ドリラー
- プレイヤーは下方向に向かってブロックを掘り進み、スコアと深さを競う。
- 「酸素(AIR)」の概念があり、時間経過で減少する。

## 2. コアメカニクス
- **移動と掘削**: 
    - 矢印キーで移動。
    - 隣接する(上下左右)ブロックを、移動キー(左、下、右)で破壊。
    - 1ブロック下に進むごとに深さを +1する
    - 破壊できたらその方向に進む
- **ブロックの挙動**:
    - ブロックの種類は4種類
    - 青色の土ブロック : 1アクションで破壊可能、破壊するのに酸素ゲージを1消費する
    - 茶色の土ブロック : 2アクションで破壊可能、破壊するのに酸素ゲージを2消費する
    - 灰色の岩ブロック : 3アクションで破壊可能、破壊するのに酸素ゲージを5消費する
    - 銀色のメタルブロック : 破壊不能、移動アクション毎に酸素ゲージを2消費する
- **リソース管理**:
    - 酸素ゲージは最大100。毎秒1ずつ減少。
    - 特定のブロック(エアーカプセル)を取得すると酸素が15回復。
    - 特定のブロックの破壊でも酸素ゲージを消費する
    - 酸素ブロックはおよそ、30メートルに1つの割合で出現する
- **ゲーム管理**:
    - 画面読み込みと同時にゲーム開始
    - 酸素ゲージ0でゲームオーバー
    - スペースキー押下で再ゲームスタート

## 3. 画面構成
- 画面の上部と下部の2部構成
- 画面上部はスコアなどの表示ゾーン
- Canvasサイズ400x100
- 画面上部に左から「DEPTH(深さ)スコア」「AIR(残り酸素)ゲージ」を表示。
- DEPTHスコアの表示は画面左上に固定し、数値4桁で0埋めする
- AIRゲージは画面上部の中央に長めに固定
- AIRゲージ全体は白枠組みで、残り酸素を黄色で表現し右から左に向かって減るようにする
- AIRゲージの右側に残り酸素を数値で表示(MAX100で3桁0埋めする)
- 画面下部はブロックゾーン
- Canvasサイズ: 400x600(縦長)
- ブロックサイズ: 40x40のグリッド
- 掘り進めるごとに、うまく調整してスクロールするようにする
- 深さ10m毎にブロックキャンバスの左外側にその深さを数値で表示させる

## 4. ビジュアル・操作性
- ブロックの色は4色(青、茶、灰、銀)、それぞれ、四角で表現し、枠は白くする
- エアーカプセルは桃色の簡易的な丸型図形とする
- キャラクターは黒色の簡易的な下向きの三角形でOK。
- 操作:
    - Left/Right:移動
    - Down:下のブロックを掘る

## 5. 実装のステップ
1. Canvasのセットアップとゲームループ(requestAnimationFrame)の作成。
2. ブロック配置データの生成(配列管理)。
3. プレイヤーの移動と掘削処理。
4. ブロックの消滅ロジックの実装。
5. 酸素減少とゲームオーバー判定の実装。

まずは、これらを網羅した動くコードを出力してください。


これをLLMに直接放り投げれば
HTMLでJSを用いたゲームを作ってもらえると思います。

是非コピペしてみてください

それでは。




 

プログラミング未経験の方のための
プログラミング学習講座を作成しました

その名も
「1時間で学べるPythonプログラミング」


講義動画はこちら




この講座は初学者の方が
短時間でPython言語を学ぶことのできる
プログラミング学習用の講座です

プログラミングが分からないない方は
Python言語を通じて
プログラミングの基礎を学習できます

講座は動画に加えてGoogle Colabを用いて
手元でコードを動かすことのできます
コードがどう動くのかを確認をしながら
進めていってください

資料はここ:
Google Colabの資料


00:00 1.はじめに
02:13 2.導入方法
02:55 3.GoogleColaboratoryの操作方法
06:19 4.Pythonの計算の基礎
27:27 5.Pythonの制御文
42:14 6.Pythonのクラス
49:11 7.Pythonのその他構文
64:30 8.まとめ

なおPythonチートシートを作成しています。

コーディングに迷った際に役に立ち

WEB検索する時間を無くして

作業時間を効率化できます。

note
Pythonチートシート


 

このページのトップヘ