Python Web制作完全攻略【Flask・Django・FastAPI徹底マスター】
Python は Web 開発において非常に人気の高いプログラミング言語です。Flask、Django、FastAPI などの優秀なフレームワークにより、シンプルなWebサイトから大規模なWebアプリケーションまで効率的に開発できます。本記事では、Python での Web制作を基本から応用まで、実用的なサンプルコードとともに徹底解説します。
Python Web開発の特徴
Python Web開発の利点
- 学習コストが低い: 読みやすい構文
- 豊富なライブラリ: 機械学習、データ分析との連携
- 高い生産性: 少ないコードで機能実装
- スケーラビリティ: 小規模から大規模まで対応
- 活発なコミュニティ: 豊富な情報とサポート
主要なWebフレームワーク
フレームワーク | 特徴 | 適用場面 | 学習難易度 |
---|---|---|---|
Flask | 軽量・シンプル | 小〜中規模、API | 低 |
Django | 高機能・多機能 | 大規模、CMS | 中〜高 |
FastAPI | 高速・型安全 | API、マイクロサービス | 中 |
Tornado | 非同期・高性能 | リアルタイム通信 | 高 |
環境構築
基本的な環境セットアップ
# 仮想環境の作成
python -m venv web_project
source web_project/bin/activate # Windows: web_project\Scripts\activate
# 基本パッケージのインストール
pip install flask django fastapi uvicorn requests
requirements.txtの作成
Flask==2.3.3
Django==4.2.7
FastAPI==0.104.1
uvicorn==0.24.0
requests==2.31.0
Flask入門
最小のFlaskアプリ
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return '<h1>Hello, Flask!</h1>'
@app.route('/user/<name>')
def user(name):
return f'<h1>Hello, {name}!</h1>'
if __name__ == '__main__':
app.run(debug=True)
HTMLテンプレート
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
users = ['Alice', 'Bob', 'Charlie']
return render_template('index.html', users=users)
@app.route('/about')
def about():
return render_template('about.html', title='About Us')
if __name__ == '__main__':
app.run(debug=True)
フォーム処理
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
@app.route('/contact', methods=['GET', 'POST'])
def contact():
if request.method == 'POST':
name = request.form['name']
email = request.form['email']
message = request.form['message']
# データ処理(保存、メール送信など)
print(f"お問い合わせ: {name} ({email}) - {message}")
return redirect(url_for('thanks'))
return render_template('contact.html')
@app.route('/thanks')
def thanks():
return '<h1>お問い合わせありがとうございました!</h1>'
if __name__ == '__main__':
app.run(debug=True)
Django入門
Djangoプロジェクトの作成
# プロジェクト作成
django-admin startproject mysite
cd mysite
# アプリケーション作成
python manage.py startapp blog
# データベース初期化
python manage.py migrate
# 開発サーバー起動
python manage.py runserver
基本的なDjangoビュー
# blog/views.py
from django.shortcuts import render
from django.http import HttpResponse
import datetime
def index(request):
return HttpResponse('<h1>Welcome to Django!</h1>')
def current_time(request):
now = datetime.datetime.now()
return HttpResponse(f'<h1>現在時刻: {now}</h1>')
def user_profile(request, user_id):
return HttpResponse(f'<h1>ユーザーID: {user_id}</h1>')
DjangoのURL設定
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('time/', views.current_time, name='time'),
path('user/<int:user_id>/', views.user_profile, name='profile'),
]
# mysite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
]
Djangoモデル
# blog/models.py
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(default=timezone.now)
published = models.BooleanField(default=False)
def __str__(self):
return self.title
class Meta:
ordering = ['-created_at']
# マイグレーション実行
# python manage.py makemigrations
# python manage.py migrate
FastAPI入門
最小のFastAPIアプリ
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
age: int
email: str
@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}
@app.get("/users/{user_id}")
def read_user(user_id: int):
return {"user_id": user_id, "name": f"User {user_id}"}
@app.post("/users/")
def create_user(user: User):
return {"message": f"User {user.name} created successfully"}
# 実行: uvicorn main:app --reload
FastAPIでのデータベース連携
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
# データベース設定
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
email = Column(String, unique=True, index=True)
Base.metadata.create_all(bind=engine)
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/users/{user_id}")
def read_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
return user
RESTful API開発
FlaskでシンプルなREST API
from flask import Flask, jsonify, request
app = Flask(__name__)
# ダミーデータ
users = [
{'id': 1, 'name': 'Alice', 'email': 'alice@example.com'},
{'id': 2, 'name': 'Bob', 'email': 'bob@example.com'}
]
@app.route('/api/users', methods=['GET'])
def get_users():
return jsonify(users)
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
user = next((u for u in users if u['id'] == user_id), None)
return jsonify(user) if user else ('Not Found', 404)
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.json
new_user = {
'id': max(u['id'] for u in users) + 1,
'name': data['name'],
'email': data['email']
}
users.append(new_user)
return jsonify(new_user), 201
if __name__ == '__main__':
app.run(debug=True)
FastAPIでの高度なAPI
from fastapi import FastAPI, HTTPException, Depends, status
from pydantic import BaseModel, EmailStr
from typing import List, Optional
import jwt
from datetime import datetime, timedelta
app = FastAPI(title="Advanced API", version="1.0.0")
class UserCreate(BaseModel):
name: str
email: EmailStr
password: str
class UserResponse(BaseModel):
id: int
name: str
email: str
created_at: datetime
# ダミーデータベース
fake_db = []
@app.post("/users/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
def create_user(user: UserCreate):
new_user = {
"id": len(fake_db) + 1,
"name": user.name,
"email": user.email,
"created_at": datetime.now()
}
fake_db.append(new_user)
return new_user
@app.get("/users/", response_model=List[UserResponse])
def list_users(skip: int = 0, limit: int = 10):
return fake_db[skip : skip + limit]
@app.get("/users/{user_id}", response_model=UserResponse)
def get_user(user_id: int):
user = next((u for u in fake_db if u["id"] == user_id), None)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
データベース連携
FlaskとSQLAlchemy
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
@app.route('/')
def index():
posts = Post.query.order_by(Post.created_at.desc()).all()
return render_template('index.html', posts=posts)
@app.route('/create', methods=['GET', 'POST'])
def create_post():
if request.method == 'POST':
post = Post(
title=request.form['title'],
content=request.form['content']
)
db.session.add(post)
db.session.commit()
return redirect(url_for('index'))
return render_template('create.html')
with app.app_context():
db.create_all()
if __name__ == '__main__':
app.run(debug=True)
DjangoのORM
# blog/models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post, Category
def post_list(request):
posts = Post.objects.select_related('category').order_by('-created_at')
return render(request, 'blog/list.html', {'posts': posts})
def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id)
return render(request, 'blog/detail.html', {'post': post})
認証とセキュリティ
Flask-Loginでの認証
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.secret_key = 'your-secret-key'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
class User(UserMixin):
def __init__(self, id, username, password_hash):
self.id = id
self.username = username
self.password_hash = password_hash
# ダミーユーザーデータ
users = {
'admin': User('1', 'admin', generate_password_hash('password'))
}
@login_manager.user_loader
def load_user(user_id):
return next((u for u in users.values() if u.id == user_id), None)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = users.get(username)
if user and check_password_hash(user.password_hash, password):
login_user(user)
return redirect(url_for('dashboard'))
else:
flash('ログイン失敗')
return render_template('login.html')
@app.route('/dashboard')
@login_required
def dashboard():
return '<h1>ダッシュボード(ログイン済み)</h1>'
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))
FastAPIでのJWT認証
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
import jwt
from datetime import datetime, timedelta
from passlib.context import CryptContext
app = FastAPI()
security = HTTPBearer()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
class UserLogin(BaseModel):
username: str
password: str
class Token(BaseModel):
access_token: str
token_type: str
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(hours=24)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
try:
payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
if username is None:
raise HTTPException(status_code=401, detail="Invalid token")
return username
except jwt.PyJWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.post("/login", response_model=Token)
def login(user: UserLogin):
# ダミー認証(実際はデータベースで確認)
if user.username == "admin" and user.password == "password":
access_token = create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}
raise HTTPException(status_code=401, detail="Incorrect credentials")
@app.get("/protected")
def protected_route(username: str = Depends(verify_token)):
return {"message": f"Hello, {username}! This is a protected route."}
フロントエンド連携
Flask + Ajax
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def index():
return render_template('ajax_demo.html')
@app.route('/api/search', methods=['POST'])
def search():
query = request.json.get('query', '')
# 検索処理(ダミー)
results = [f"結果{i}: {query}" for i in range(1, 4)]
return jsonify({'results': results})
@app.route('/api/users/<int:user_id>')
def get_user_api(user_id):
# ダミーユーザーデータ
user = {'id': user_id, 'name': f'User {user_id}', 'email': f'user{user_id}@example.com'}
return jsonify(user)
if __name__ == '__main__':
app.run(debug=True)
FastAPIでのCORS設定
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
app = FastAPI()
# CORS設定
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"], # React開発サーバーなど
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class Item(BaseModel):
name: str
price: float
@app.get("/api/items")
def get_items():
return [
{"id": 1, "name": "商品A", "price": 1000},
{"id": 2, "name": "商品B", "price": 2000}
]
@app.post("/api/items")
def create_item(item: Item):
return {"message": f"商品 '{item.name}' を作成しました", "item": item}
デプロイメント
Herokuへのデプロイ
# Procfile
web: gunicorn app:app
# requirements.txt
Flask==2.3.3
gunicorn==21.2.0
# runtime.txt
python-3.11.6
# app.py (Heroku対応)
import os
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return '<h1>Hello, Heroku!</h1>'
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
Dockerでのコンテナ化
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
パフォーマンス最適化
キャッシング
from flask import Flask
from flask_caching import Cache
app = Flask(__name__)
app.config['CACHE_TYPE'] = 'simple'
cache = Cache(app)
@app.route('/expensive-operation')
@cache.cached(timeout=300) # 5分間キャッシュ
def expensive_operation():
# 重い処理のシミュレーション
import time
time.sleep(2)
return {'result': 'heavy computation completed'}
@app.route('/user/<int:user_id>')
@cache.cached(timeout=60, key_prefix='user')
def get_user(user_id):
# データベースクエリのシミュレーション
return {'user_id': user_id, 'name': f'User {user_id}'}
if __name__ == '__main__':
app.run(debug=True)
非同期処理とWebSocket
from fastapi import FastAPI, WebSocket
import asyncio
import json
app = FastAPI()
class ConnectionManager:
def __init__(self):
self.active_connections: list[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await manager.connect(websocket)
try:
while True:
data = await websocket.receive_text()
await manager.broadcast(f"ブロードキャスト: {data}")
except Exception:
manager.disconnect(websocket)
@app.get("/")
def index():
return {"message": "WebSocket server running"}
テストとデバッグ
Flaskアプリのテスト
import pytest
from app import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_index(client):
response = client.get('/')
assert response.status_code == 200
assert b'Hello' in response.data
def test_api_users(client):
response = client.get('/api/users')
assert response.status_code == 200
data = response.get_json()
assert isinstance(data, list)
def test_create_user(client):
response = client.post('/api/users',
json={'name': 'Test User', 'email': 'test@example.com'})
assert response.status_code == 201
FastAPIのテスト
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello, FastAPI!"}
def test_create_user():
response = client.post("/users/",
json={"name": "Test", "age": 25, "email": "test@example.com"})
assert response.status_code == 200
assert response.json()["message"] == "User Test created successfully"
まとめ
Python での Web 制作は、用途に応じて適切なフレームワークを選択することで効率的な開発が可能です。各フレームワークの特徴を理解し、プロジェクトの要件に最適な技術選択を行うことが重要です。
フレームワーク選択の指針:
- Flask: 小規模、カスタマイズ性重視、学習目的
- Django: 大規模、短期開発、CMS・管理画面
- FastAPI: API開発、高性能、型安全性
重要な技術要素:
- ルーティング: URLとビューの関連付け
- テンプレート: HTMLの動的生成
- データベース: ORM を使った効率的なデータ操作
- 認証・セキュリティ: ユーザー管理と保護
- API設計: RESTful または GraphQL
- デプロイ: クラウドサービスやコンテナ技術
ベストプラクティス:
- 仮想環境でのパッケージ管理
- 環境変数での設定管理
- 適切なエラーハンドリング
- テストコードの作成
- セキュリティ対策の実装
- パフォーマンス最適化
本記事のサンプルコードを参考に、あなたのプロジェクトに最適な Web アプリケーションを開発してください。継続的な学習により、より高度で実用的な Web システムを構築できます。
参考文献
- Flask公式ドキュメント
- Django公式ドキュメント
- FastAPI公式ドキュメント
- Python Web Development with Flask
- Two Scoops of Django
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座