From django-pro
Django ORM, DRF, signals, management commands, Celery, testing. Use when building or reviewing Django applications.
How this skill is triggered — by the user, by Claude, or both
Slash command
/django-pro:django-proThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build production-grade Django applications with clean project structure, optimized ORM queries, DRF best practices, Celery background tasks, and comprehensive testing.
Build production-grade Django applications with clean project structure, optimized ORM queries, DRF best practices, Celery background tasks, and comprehensive testing.
Use this when:
Use this ESPECIALLY when:
Don't skip when:
project/
settings/
base.py ← Shared settings
development.py
production.py
test.py
urls.py ← Root URL config
wsgi.py / asgi.py
apps/
projects/
migrations/
templates/
__init__.py
admin.py
apps.py
models.py ← Project, Task, ProjectMember
serializers.py ← DRF serializers
views.py ← API views / viewsets
urls.py
filters.py ← django-filter
permissions.py
signals.py
tasks.py ← Celery tasks
tests/
test_models.py
test_views.py
test_services.py
management/
commands/
backfill_project_stats.py
templates/
static/
media/
# apps/projects/models.py
import uuid
from django.db import models
from django.utils import timezone
from django.core.validators import MinLengthValidator
class Project(models.Model):
class Status(models.TextChoices):
ACTIVE = "active", "Active"
ARCHIVED = "archived", "Archived"
DELETED = "deleted", "Deleted"
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=100, validators=[MinLengthValidator(1)])
description = models.TextField(blank=True, default="")
owner = models.ForeignKey(
"users.User",
on_delete=models.CASCADE,
related_name="projects",
)
status = models.CharField(
max_length=20, choices=Status.choices, default=Status.ACTIVE
)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-created_at"]
indexes = [
models.Index(fields=["owner", "status"]),
models.Index(fields=["created_at"]),
]
def __str__(self):
return self.name
# apps/projects/views.py
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
class ProjectViewSet(viewsets.ModelViewSet):
serializer_class = ProjectSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend]
filterset_fields = ["status"]
def get_queryset(self):
return Project.objects.filter(owner=self.request.user)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
@action(detail=True, methods=["post"])
def archive(self, request, pk=None):
project = self.get_object()
project.status = Project.Status.ARCHIVED
project.save()
return Response({"status": "archived"})
# ✅ Select related (avoid N+1)
projects = Project.objects.select_related("owner").all()
# ✅ Prefetch related (for reverse relations)
projects = Project.objects.prefetch_related("tasks").all()
# ✅ Only needed fields
projects = Project.objects.only("id", "name", "owner_id")
# ✅ Batch operations
Project.objects.filter(status="archived").update(status="deleted")
# ❌ Never do this in a loop
for project in projects:
print(project.tasks.count()) # N queries!
# apps/projects/tasks.py
from celery import shared_task
from django.utils import timezone
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def generate_project_report(self, project_id):
try:
project = Project.objects.get(id=project_id)
report = ReportGenerator.generate(project)
return {"project_id": str(project.id), "report_id": str(report.id)}
except Project.DoesNotExist:
logger.error(f"Project {project_id} not found")
return None
except Exception as exc:
raise self.retry(exc=exc)
# apps/projects/signals.py
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
@receiver(post_save, sender=Project)
def project_created_handler(sender, instance, created, **kwargs):
if created:
# Create default project settings
ProjectSettings.objects.create(project=instance)
# Send notification
notify_user(instance.owner, f"Project '{instance.name}' created")
UserRateThrottle)Provides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.
npx claudepluginhub haj1t/senior-dev-squad-skills --plugin django-pro