mcpField
D
django-coder

django-coder

github.com/majesticlabs-dev开发5065 次安装7 周前更新
代码仓库

关于 django-coder

面向 Django 开发者的开发技能,涵盖 Web 应用结构、模型、视图和 API 的实践模式与示例。

主要功能

  1. 01标准 Django 项目结构
  2. 02模型与管理器模式
  3. 03类视图与异步视图
  4. 04Django REST Framework 示例
  5. 05服务层与质量检查清单

适用场景

  1. 01组织新的 Django 项目
  2. 02规划业务逻辑与视图
  3. 03使用 Django 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