django-patterns について
Django 開発者向けの設計パターンガイドです。プロジェクトのレイヤー構成、ORM クエリの最適化、REST Framework のシリアライザー、ミドルウェアを扱い、シグナルの用途やテスト項目も示します。
主な機能
- 01プロジェクト構成とビジネスロジックの分離
- 02select_related と prefetch_related
- 03REST Framework シリアライザー
- 04アプリ間の副作用とシグナル
- 05カスタムミドルウェアのパターン
- 06アンチパターンとテスト項目
活用シーン
- 01Django プロジェクトのモジュール構成の計画
- 02ORM の N+1 クエリ問題の削減
- 03API のシリアライズと入力検証の設計
- 04ビュー、シグナル、テスト実践の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rohitg00/ awesome-claude-code-toolkit --skill django-patternsインストール後、Claude Code で/django-patternsを入力して読み込まれたか確認します。
詳細
Django のパターン
プロジェクト構成
アプリ、共通ユーティリティ、設定を明確に分けて、Django プロジェクトを構成します。
project/
config/
settings/
base.py
local.py
production.py
urls.py
wsgi.py
apps/
users/
models.py
serializers.py
views.py
services.py
selectors.py
urls.py
tests/
orders/
...
common/
models.py
permissions.py
pagination.py
書き込み処理は services.py に、読み取り処理は selectors.py にビジネスロジックを記述します。ビューは薄く保ちます。
ORM の最適化
# select_related for ForeignKey / OneToOne (SQL JOIN)
orders = Order.objects.select_related("customer", "customer__profile").all()
# prefetch_related for ManyToMany / reverse FK (separate query)
authors = Author.objects.prefetch_related(
Prefetch("books", queryset=Book.objects.filter(published=True))
).all()
# Defer fields you don't need
posts = Post.objects.defer("body", "metadata").filter(status="published")
# Use .only() when you need just a few columns
emails = User.objects.only("id", "email").filter(is_active=True)
# Bulk operations
Product.objects.bulk_create(products, batch_size=1000)
Product.objects.bulk_update(products, ["price", "stock"], batch_size=1000)
テストでは必ず django-debug-toolbar または connection.queries を使ってクエリを確認します。
Django REST Framework のシリアライザー
class OrderSerializer(serializers.ModelSerializer):
customer_name = serializers.CharField(source="customer.full_name", read_only=True)
items = OrderItemSerializer(many=True, read_only=True)
total = serializers.SerializerMethodField()
class Meta:
model = Order
fields = ["id", "customer_name", "items", "total", "created_at"]
read_only_fields = ["id", "created_at"]
def get_total(self, obj):
return sum(item.price * item.quantity for item in obj.items.all())
def validate(self, data):
if data.get("start_date") and data.get("end_date"):
if data["start_date"] >= data["end_date"]:
raise serializers.ValidationError("end_date must be after start_date")
return data
シグナル
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Order)
def order_created_handler(sender, instance, created, **kwargs):
if created:
send_order_confirmation.delay(instance.id)
update_inventory.delay(instance.id)
アプリ間の副作用にはシグナルを使用します。同じアプリ内のロジックでは、サービスを直接呼び出します。
カスタムミドルウェア
import time
import logging
logger = logging.getLogger(__name__)
class RequestTimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.monotonic()
response = self.get_response(request)
duration = time.monotonic() - start
logger.info(f"{request.method} {request.path} {response.status_code} {duration:.3f}s")
return response
アンチパターン
- サービスレイヤーではなく、ビューやシリアライザーにビジネスロジックを記述する
- リストエンドポイントでページネーションを使わずに
Model.objects.all()を使用する select_related/prefetch_relatedの指定漏れによる N+1 クエリ- 同じアプリ内のロジックでシグナルを使いすぎる(処理の流れを追いにくくする)
- 環境変数ではなく、
settings.pyにシークレットを保存する - パラメーター化クエリを使わずに生の SQL を実行する
チェックリスト
- ビジネスロジックがビューではなく、サービスやセレクターに記述されている
- 必要に応じて、すべてのリストクエリで
select_relatedまたはprefetch_relatedを使用している - シリアライザーがカスタム
validateメソッドで入力データを検証している - 設定が base/local/production の各モジュールに分割されている
- マージ前にマイグレーションがレビューされている
- 一括挿入・更新に一括操作を使用している
- カスタムミドルウェアが WSGI 呼び出し可能オブジェクトのパターンに従っている
- テストでモデルの制約、シリアライザーの検証、ビューの権限を網羅している
コメント
Markdown 対応