mcpField
D
django-clean-drf

django-clean-drf

github.com/agusabas開発548 回インストール33 週間前に更新
リポジトリ

django-clean-drf について

Clean Architectureに沿ったDjango REST Frameworkアプリ開発を支援するスキルです。レイヤー構造と内向きの依存関係を重視し、ユースケース、サービス、薄いビュー、シリアライザー、テスト、API開発のパターンを示します。

主な機能

  1. 01レイヤー構造と内向き依存
  2. 02入出力DTOを使うユースケース
  3. 03サービス層のドメインロジック
  4. 04薄いビューと読み書き用シリアライザーの分離
  5. 05型ヒントとテスト容易性の指針
  6. 06アーキテクチャとAPIの参考資料

活用シーン

  1. 01Django REST Frameworkアプリの新規構築
  2. 02業務ロジックをユースケースとサービスに分割
  3. 03CRUDエンドポイントとシリアライザーの実装
  4. 04テスト可能なDjango APIコードの作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/agusabas/django-skills --skill django-clean-drf

インストール後、Claude Code で/django-clean-drfを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api-patterns.md
authentication.md
coding-standards.md
django-admin.md
examples.md
models-domain.md
production-api.md
project-structure.md
query-optimization.md
services-pattern.md
testing-clean-arch.md
use-cases-pattern.md
views-serializers.md

詳細

Django Clean DRF アーキテクト

概要

このスキルは、クリーンアーキテクチャの原則に従って Django REST Framework アプリケーションを作成するための専門的なガイダンスを提供します。関心事を分離し、テスト容易性を最大限に高め、保守しやすい本番品質のコードを生成する、厳格なレイヤーアーキテクチャを適用します。

アーキテクチャのレイヤー:

HTTP Layer (Views/Serializers)
    ↓
Application Layer (Use Cases + DTOs)
    ↓
Domain Layer (Services + Models)
    ↓
Infrastructure Layer (ORM, External APIs, Cache)

主な機能:

  • 厳格な依存関係ルールを備えたレイヤーアーキテクチャ(依存関係は内側にのみ向かいます)
  • データクラスの入力/出力 DTO を使用したユースケースパターン
  • ドメインロジックのサービスレイヤー(静的クエリ、インスタンスの変更)
  • ユースケースに処理を委譲する薄いビュー
  • 読み取り用と作成/更新用のシリアライザーを分離
  • ビジネスロジックで例外を使わない明示的なエラーハンドリング
  • 最新の Python 3.12+ および Django 5+ の機能
  • 完全な型ヒントと、設計段階からのテスト容易性

使用するタイミング

次のような状況に遭遇した場合に、このスキルを呼び出してください。

新しいアプリケーションのセットアップ:

  • 「次のような新しい Django API を作成して……」
  • 「クリーンアーキテクチャで新しい DRF プロジェクトを始めて」
  • 「レイヤーアーキテクチャで新しいアプリをセットアップして」
  • 「ドメイン駆動の Django アプリケーションを初期化して」
  • 「SOLID に従った Django アプリのひな形を作成して」

ユースケースの実装:

  • 「次のユースケースを作成して……」
  • 「次のビジネスロジックを実装して……」
  • 「新しい操作/アクションを追加して……」
  • 「このトランザクションをアトミックに処理して」

サービスレイヤー:

  • 「次のサービスを作成して……」
  • 「このビジネスロジックはどこに配置すればよいですか?」
  • 「次のドメイン検証を実装して……」
  • 「クリーンアーキテクチャに従ってデータをクエリして」

アーキテクチャに関する質問:

  • 「この Django アプリはどのように構成すればよいですか?」
  • 「次の処理はどのレイヤーで扱えばよいですか?」
  • 「肥大化したビュー/モデルを避けるにはどうすればよいですか?」
  • 「テストしやすくするにはどうすればよいですか?」
  • 「Django に SOLID の原則を適用して」

API 設計:

  • 「次の API エンドポイントを作成して……」
  • 「シリアライザーを設計して……」
  • 「このエンティティの CRUD を実装して」

手順

Django Clean DRF に関するリクエストに対応する際は、次のワークフローに従ってください。

1. 要件を分析してコンテキストを確立する

ドメインを理解する:

  • 関連するエンティティ/モデルは何ですか?
  • 必要な操作/アクションは何ですか?
  • 適用すべきビジネスルールは何ですか?
  • 外部依存関係(API、キュー)はありますか?

既存のプロジェクト構成を確認する:

  • 既存のアプリとその構成を確認する
  • すでに使用されているパターンを特定する
  • 機能の利用可否を確認するため、Django/Python のバージョンを確認する

スコープを判断する:

  • 単一のユースケースですか、それとも完全な CRUD ですか?
  • 新しいアプリですか、それとも既存アプリの拡張ですか?
  • API のみですか、それとも管理画面も含みますか?
2. 関連するリファレンスドキュメントを読み込む

タスクに応じて、同梱ドキュメントの該当箇所を参照してください。

アーキテクチャ:

  • 新しいアプリのセットアップ → references/project-structure.md
  • ユースケースの実装 → references/use-cases-pattern.md
  • サービスレイヤー → references/services-pattern.md
  • モデルとドメインロジック → references/models-domain.md
  • ビューとシリアライザー → references/views-serializers.md
  • テスト → references/testing-clean-arch.md
  • 完全な例 → references/examples.md

API 開発:

  • クエリの最適化/N+1 → references/query-optimization.md
  • ページネーション、フィルタリング、検索 → references/api-patterns.md
  • 認証/JWT/権限 → references/authentication.md
  • 本番環境へのデプロイ → references/production-api.md
  • API 向け Django Admin → references/django-admin.md

コード品質:

  • コーディング規約/Ruff/セキュリティ → references/coding-standards.md
3. クリーンアーキテクチャの原則に従って実装する

重要:レイヤーの依存関係ルール

Views → Use Cases → Services → Models
  ↓         ↓           ↓         ↓
Serializers  DTOs    (internal)   ORM
  • 依存関係は内側にのみ向かいます(外側のレイヤーが内側のレイヤーに依存します)
  • ユースケースでビューをインポートしたり、サービスでユースケースをインポートしたりしてはいけません

ユースケースパターン:

from dataclasses import dataclass
from uuid import UUID
from django.db import transaction

@dataclass(frozen=True, slots=True)
class CreateOrderInput:
    customer_id: UUID
    items: list['OrderItemInput']
    notes: str | None = None

@dataclass(frozen=True, slots=True)
class CreateOrderOutput:
    success: bool
    order_id: UUID | None = None
    error: str | None = None

class CreateOrderUseCase:
    def __init__(
        self,
        order_service: OrderService,
        inventory_service: InventoryService,
    ):
        self._order_service = order_service
        self._inventory_service = inventory_service

    @transaction.atomic
    def execute(self, input_dto: CreateOrderInput) -> CreateOrderOutput:
        # Validate
        is_valid, error = self._inventory_service.validate_availability(input_dto.items)
        if not is_valid:
            return CreateOrderOutput(success=False, error=error)

        # Execute
        order = self._order_service.create(
            customer_id=input_dto.customer_id,
            items=input_dto.items,
        )
        return CreateOrderOutput(success=True, order_id=order.id)

サービスパターン:

class OrderService:
    # STATIC methods for QUERIES (no state changes)
    @staticmethod
    def get_by_id(order_id: UUID) -> Order | None:
        return Order.objects.select_related('customer').filter(id=order_id).first()

    # INSTANCE methods for MUTATIONS (state changes)
    def create(self, customer_id: UUID, items: list[OrderItemInput]) -> Order:
        order = Order.objects.create(customer_id=customer_id)
        for item in items:
            OrderItem.objects.create(order=order, **item.__dict__)
        return order

    # VALIDATION returns tuple[bool, str]
    def validate_can_cancel(self, order: Order) -> tuple[bool, str]:
        if order.status == Order.Status.SHIPPED:
            return False, "Cannot cancel shipped orders"
        return True, ""

薄いビューパターン:

class CreateOrderView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request: Request) -> Response:
        serializer = CreateOrderSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        use_case = CreateOrderUseCase(
            order_service=OrderService(),
            inventory_service=InventoryService(),
        )
        input_dto = CreateOrderInput(**serializer.validated_data)
        output = use_case.execute(input_dto)

        if not output.success:
            return Response({'error': output.error}, status=400)
        return Response({'order_id': str(output.order_id)}, status=201)

シリアライザーの分離:

# WRITE serializer (input validation)
class CreateOrderSerializer(serializers.Serializer):
    items = OrderItemInputSerializer(many=True, min_length=1)
    notes = serializers.CharField(max_length=500, required=False)

# READ serializer (output display)
class OrderReadSerializer(serializers.ModelSerializer):
    customer_name = serializers.CharField(source='customer.name', read_only=True)

    class Meta:
        model = Order
        fields = ['id', 'customer_name', 'status', 'created_at']
        read_only_fields = fields

ドメインロジックを備えたモデル:

class Order(models.Model):
    class Status(models.TextChoices):
        PENDING = 'pending', 'Pending'
        CONFIRMED = 'confirmed', 'Confirmed'
        SHIPPED = 'shipped', 'Shipped'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    customer = models.ForeignKey('Customer', on_delete=models.PROTECT, related_name='orders')
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.PENDING)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']
        indexes = [models.Index(fields=['customer', 'status'])]

    @property
    def is_cancellable(self) -> bool:
        return self.status in (self.Status.PENDING, self.Status.CONFIRMED)
4. 検証と仕上げ

アーキテクチャのチェックリスト:

  • ビューは薄く保ちます(ロジックは20行未満)
  • ユースケースは単一の操作を処理します
  • サービスには再利用可能なドメインロジックを記述します
  • 依存関係は内側にのみ向かいます
  • レイヤー間に循環インポートはありません

コード品質のチェックリスト:

  • すべての公開インターフェースに型ヒントを付けます
  • データクラスのDTOはslots付きのfrozenにします
  • ビジネスロジックのエラーに例外を使わず、Outputを返します
  • バリデーションはtuple[bool, str]を返します
  • 状態変更を@transaction.atomicで囲みます

パフォーマンスのチェックリスト:

  • ForeignKeyへのアクセスにはselect_relatedを使います
  • 逆リレーションにはprefetch_relatedを使います
  • 頻繁にクエリされるフィールドにインデックスを設定します
  • シリアライザーでN+1クエリが発生しないようにします

ディレクトリ構造

apps/<app_name>/
├── __init__.py
├── models.py              # Domain entities with @property logic
├── views.py               # Thin HTTP handlers
├── serializers.py         # Read and Write serializers
├── urls.py                # Route definitions
├── admin.py               # Django Admin
├── services/
│   ├── __init__.py        # Export services
│   └── <entity>_service.py
├── use_cases/
│   ├── __init__.py        # Export use cases
│   └── <action>_<entity>.py  # One file per use case
├── tests/
│   ├── __init__.py
│   ├── test_models.py
│   ├── test_services.py
│   ├── test_use_cases.py
│   ├── test_views.py
│   └── factories.py       # Factory Boy factories
└── migrations/

同梱リソース

references/ - クリーンアーキテクチャとAPIに関する包括的なドキュメント

アーキテクチャのパターン
  • references/project-structure.md ディレクトリ構成、ファイルの命名、モジュールの構成、依存関係のルール

  • references/use-cases-pattern.md Input/Output DTO、コンストラクターインジェクション、トランザクション処理、エラー処理

  • references/services-pattern.md 静的メソッドとインスタンスメソッド、バリデーションのパターン、サービス間の連携

  • `references/models-domain.md`` モデル内のドメインロジック、TextChoices、UUIDキー、インデックス

  • references/views-serializers.md 薄いビュー、権限、ReadシリアライザーとWriteシリアライザー

  • references/testing-clean-arch.md ユースケースの単体テスト、サービスのモック化、統合テスト

  • references/examples.md CRUDの完全な例、複雑なワークフロー、テストの例

APIのベストプラクティス
  • references/query-optimization.md N+1クエリ、select_related/prefetch_related、インデックス、一括操作、集計

  • references/api-patterns.md ページネーション、フィルタリング、検索、並べ替え、APIバージョニング、エラー処理、スロットリング

  • references/authentication.md JWT認証、権限、APIキー、ロールベースのアクセス制御、セキュリティヘッダー

  • references/production-api.md 設定の構成、データベース設定、キャッシュ、ロギング、Sentry、ヘルスチェック、Docker

  • references/django-admin.md ModelAdminの設定、インライン、カスタムアクション、クエリの最適化、権限、セキュリティ

コード品質
  • references/coding-standards.md Ruffの設定、インポートの順序、セキュリティの実践、YAGNI、ロギング、ドキュメント

コア原則

ビジネスロジックに例外を使わない
# BAD
def create_order(self, data):
    if not self.can_create():
        raise ValidationError("Cannot create order")
    return Order.objects.create(**data)

# GOOD
def create_order(self, data) -> CreateOrderOutput:
    if not self.can_create():
        return CreateOrderOutput(success=False, error="Cannot create order")
    order = Order.objects.create(**data)
    return CreateOrderOutput(success=True, order_id=order.id)
バリデーションはタプルを返す
# BAD
def validate(self, order) -> bool:
    return order.status != 'shipped'

# GOOD
def validate(self, order) -> tuple[bool, str]:
    if order.status == 'shipped':
        return False, "Cannot modify shipped orders"
    return True, ""
テスト容易性を高めるコンストラクターインジェクション
# BAD - Hard to test
class CreateOrderUseCase:
    def execute(self, input_dto):
        service = OrderService()  # Hardcoded dependency
        return service.create(input_dto)

# GOOD - Easy to mock
class CreateOrderUseCase:
    def __init__(self, order_service: OrderService):
        self._order_service = order_service

    def execute(self, input_dto):
        return self._order_service.create(input_dto)

追加の注意事項

Pythonのバージョン: X | Noneのユニオン構文を使うには3.10以上が必要です。3.12以上を推奨します
Djangoのバージョン: 4.2 LTS以上が必要です。5.0以上を推奨します

命名規則:

  • ユースケース:<action>_<entity>.py(例:create_order.py)
  • サービス:<entity>_service.py(例:order_service.py)
  • シリアライザー:<Entity>ReadSerializer、<Entity>CreateSerializer

他のスキルとの連携:

  • バックグラウンドタスクにはdjango-celery-expertを使います
  • 既存のコードをこのアーキテクチャに移行するにはrefactordjangoを使います

コメント