django-coder について
Django で Web アプリケーションを開発する人向けのスキルです。プロジェクト構成、モデル、ビュー、API のパターンと例を示します。
主な機能
- 01標準的な Django 構成
- 02モデルとマネージャーのパターン
- 03クラスベースビューと非同期ビュー
- 04Django REST Framework の例
- 05サービス層と品質チェックリスト
活用シーン
- 01新しい Django プロジェクトの構成
- 02ビジネスロジックとビューの整理
- 03Django REST Framework による REST エンドポイントの構築
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ majesticlabs-dev/ majestic-marketplace --skill django-coderインストール後、Claude Code で/django-coderを入力して読み込まれたか確認します。
詳細
Django Coder
基本原則
| 原則 | 適用方法 |
|---|---|
| 設定より規約 | Django の標準的なプロジェクト構成に従う |
| DRY | モデルの継承、ミックスイン、テンプレートの継承を使用する |
| ファットモデル、シンビュー | ビジネスロジックはモデルやマネージャーに記述し、ビューは処理を調整するだけにする |
| セキュリティを最優先 | CSRF、SQL インジェクション対策、XSS 防止機能が組み込まれている |
| 暗黙的より明示的 | URL ルーティングを明確にし、インポートを明示する |
プロジェクト構成
project/
├── manage.py
├── config/ # Project settings
│ ├── __init__.py
│ ├── settings/
│ │ ├── base.py
│ │ ├── local.py
│ │ └── production.py
│ ├── urls.py
│ └── wsgi.py
├── apps/
│ └── users/ # App per domain
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── models.py
│ ├── urls.py
│ ├── views.py
│ ├── services.py # Business logic
│ ├── selectors.py # Query logic
│ └── tests/
├── templates/
│ ├── base.html
│ └── users/
└── static/
モデル
モデルの定義
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
"""Custom user model."""
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to="avatars/", blank=True)
class Meta:
ordering = ["-date_joined"]
def __str__(self):
return self.email
class Post(models.Model):
"""Blog post model."""
class Status(models.TextChoices):
DRAFT = "draft", "Draft"
PUBLISHED = "published", "Published"
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
content = models.TextField()
status = models.CharField(max_length=10, choices=Status.choices, default=Status.DRAFT)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-created_at"]
indexes = [
models.Index(fields=["slug"]),
models.Index(fields=["status", "-created_at"]),
]
カスタムマネージャー
class PublishedManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(status=Post.Status.PUBLISHED)
class Post(models.Model):
# ... fields ...
objects = models.Manager()
published = PublishedManager()
ビュー
クラスベースビュー
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
class PostListView(ListView):
model = Post
queryset = Post.published.all()
context_object_name = "posts"
paginate_by = 10
template_name = "posts/list.html"
class PostDetailView(DetailView):
model = Post
slug_field = "slug"
slug_url_kwarg = "slug"
template_name = "posts/detail.html"
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ["title", "content", "status"]
template_name = "posts/form.html"
success_url = reverse_lazy("posts:list")
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
非同期ビュー(Django 4.1+)
from django.http import JsonResponse
from asgiref.sync import sync_to_async
async def async_post_list(request):
posts = await sync_to_async(list)(Post.published.all()[:10])
data = [{"title": p.title, "slug": p.slug} for p in posts]
return JsonResponse({"posts": data})
Django REST Framework
シリアライザー
from rest_framework import serializers
class PostSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
class Meta:
model = Post
fields = ["id", "title", "slug", "author", "content", "status", "created_at"]
read_only_fields = ["slug", "created_at"]
class PostCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ["title", "content", "status"]
def create(self, validated_data):
validated_data["author"] = self.context["request"].user
return super().create(validated_data)
ビューセット
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
lookup_field = "slug"
def get_queryset(self):
if self.action == "list":
return Post.published.all()
return Post.objects.all()
def get_serializer_class(self):
if self.action == "create":
return PostCreateSerializer
return PostSerializer
@action(detail=True, methods=["post"])
def publish(self, request, slug=None):
post = self.get_object()
post.status = Post.Status.PUBLISHED
post.save()
return Response({"status": "published"})
サービスパターン
# apps/posts/services.py
from django.db import transaction
from .models import Post
class PostService:
@staticmethod
@transaction.atomic
def create_post(*, author, title: str, content: str) -> Post:
post = Post.objects.create(
author=author,
title=title,
content=content,
status=Post.Status.DRAFT,
)
return post
@staticmethod
def publish_post(*, post: Post) -> Post:
post.status = Post.Status.PUBLISHED
post.save(update_fields=["status", "updated_at"])
return post
品質チェックリスト
- プロジェクト開始時にカスタム User モデルを作成する
- アプリをドメインごとに整理する
- ファットモデル、シンビューにする
- 複雑なビジネスロジックにはサービスを使用する
- クエリ可能なフィールドに適切なインデックスを設定する
- フォームで CSRF 保護を有効にする
- 必要な箇所でログインを必須にする
- ForeignKey に適切な related_name を設定する
- モデル、ビュー、サービスのテストを作成する
よくある間違い
| 間違い | 修正方法 |
|---|---|
| カスタム User モデルがない | 必ず AbstractUser から始める |
| ビューにロジックを記述する | サービスやモデルに移す |
| N+1 クエリ | select_related/prefetch_related を使用する |
| インデックスがない | 絞り込みや並べ替えに使うフィールドにインデックスを追加する |
| URL をハードコードする | reverse() と {% url %} を使用する |
コメント
Markdown 対応