关于 django-coder
面向 Django 开发者的开发技能,涵盖 Web 应用结构、模型、视图和 API 的实践模式与示例。
主要功能
- 01标准 Django 项目结构
- 02模型与管理器模式
- 03类视图与异步视图
- 04Django REST Framework 示例
- 05服务层与质量检查清单
适用场景
- 01组织新的 Django 项目
- 02规划业务逻辑与视图
- 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