Skip to content
Back to skills

Django Patterns

ASecurity

Provides expert-level Django development patterns covering App Router (indirectly via REST/GraphQL), async views, DRF, Celery, signals, middleware, and performance optimization. Use when building complex Django 5.x applications or identifying N+1 query issues.

  • 71 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
data-aipythongobashsqlexpressdjangobackendsecurityperformance

Works with

  • cursor

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add tranhieutt/software_development_department --skill django-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Django Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Django Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tranhieutt-django-patterns/badge)](https://www.skillsdirectory.com/skills/tranhieutt-django-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: django-patterns
type: reference
description: "Provides expert-level Django development patterns covering App Router (indirectly via REST/GraphQL), async views, DRF, Celery, signals, middleware, and performance optimization. Use when building complex Django 5.x applications or identifying N+1 query issues."
paths: ["**/*.py", "**/manage.py", "**/settings.py", "**/urls.py", "**/serializers.py"]
effort: 3
allowed-tools: Read, Glob, Grep, Write, Edit, Bash
user-invocable: true
when_to_use: "When building Django 5.x applications requiring async support, background tasks (Celery), real-time features (Channels), or advanced ORM optimization."
---

# Django & DRF Professional Patterns

## Core Expertise
- **Modern Django:** 5.x features, async views/middleware, ASGI deployment.
- **Background & Real-time:** Celery integration, Django Channels.
- **ORM Optimization:** select_related, prefetch_related, custom managers.
- **Security:** JWT auth, OAuth2, RBAC, protection against SQLi/XSS/CSRF.

## Critical rules (non-obvious)

- **N+1 queries**: always use `select_related` (FK) / `prefetch_related` (M2M) — never iterate and query inside loops
- **`get_or_create` race condition**: wrap in `transaction.atomic()` in concurrent environments
- **Never call `save()` inside `pre_save` signal** — causes infinite recursion; use `update_fields`
- **`bulk_create` skips signals and `save()`** — don't use when signal logic is required
- **Migrations on large tables**: use `RunSQL` with `CONCURRENTLY` index creation to avoid locks

## ORM: select_related vs prefetch_related

```python
# FK / OneToOne → select_related (JOIN)
books = Book.objects.select_related("author", "author__publisher").all()

# M2M / reverse FK → prefetch_related (separate query)
authors = Author.objects.prefetch_related("books", "books__tags").all()

# Custom prefetch with queryset
from django.db.models import Prefetch
Author.objects.prefetch_related(
    Prefetch("books", queryset=Book.objects.filter(published=True), to_attr="active_books")
)
```

## ORM: annotations and aggregations

```python
from django.db.models import Count, Avg, Q, F, Value
from django.db.models.functions import Coalesce

Author.objects.annotate(
    book_count=Count("books"),
    avg_rating=Coalesce(Avg("books__rating"), Value(0.0)),
    high_rated=Count("books", filter=Q(books__rating__gte=4)),
).filter(book_count__gt=0).order_by("-book_count")
```

## ORM: F expressions (avoid race conditions)

```python
# BAD — race condition
product = Product.objects.get(pk=pk)
product.stock -= quantity
product.save()

# GOOD — atomic at DB level
Product.objects.filter(pk=pk).update(stock=F("stock") - quantity)
```

## Views: class-based view pattern

```python
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin

class OrderDetailView(LoginRequiredMixin, View):
    def get(self, request, pk):
        order = get_object_or_404(Order.objects.select_related("user"), pk=pk, user=request.user)
        return JsonResponse(OrderSerializer(order).data)
```

## DRF: serializer with validation

```python
class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ["id", "name", "price", "stock"]
        read_only_fields = ["id"]

    def validate_price(self, value):
        if value <= 0:
            raise serializers.ValidationError("Price must be positive.")
        return value

    def validate(self, data):  # cross-field
        if data["stock"] == 0 and data.get("is_featured"):
            raise serializers.ValidationError("Out-of-stock products cannot be featured.")
        return data
```

## DRF: ViewSet with custom actions

```python
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.select_related("category")
    serializer_class = ProductSerializer
    permission_classes = [IsAuthenticated]

    @action(detail=True, methods=["post"], url_path="archive")
    def archive(self, request, pk=None):
        product = self.get_object()
        product.is_archived = True
        product.save(update_fields=["is_archived"])
        return Response(status=status.HTTP_204_NO_CONTENT)
```

## DRF: filtering + pagination

```python
# settings.py
REST_FRAMEWORK = {
    "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.CursorPagination",
    "PAGE_SIZE": 20,
}

# viewset
class ProductViewSet(viewsets.ReadOnlyModelViewSet):
    filterset_fields = {"price": ["gte", "lte"], "category": ["exact"]}
    ordering_fields = ["price", "created_at"]
    search_fields = ["name", "description"]
```

## Celery task pattern

```python
from celery import shared_task
from django.db import transaction

@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_order_email(self, order_id: int):
    try:
        order = Order.objects.select_related("user").get(pk=order_id)
        send_email(order.user.email, order)
    except Order.DoesNotExist:
        return  # don't retry if deleted
    except Exception as exc:
        raise self.retry(exc=exc)

# Dispatch after DB commit — avoids race condition
def create_order(data):
    with transaction.atomic():
        order = Order.objects.create(**data)
        transaction.on_commit(lambda: send_order_email.delay(order.pk))
```

## Common pitfalls

| Pitfall | Fix |
|---|---|
| N+1 queries in serializer | `select_related` / `prefetch_related` on queryset |
| `objects.all()` in views | Always filter + limit; never expose unbounded querysets |
| Storing secrets in settings.py | Use `django-environ` or environment variables |
| `DateTimeField(auto_now_add=True)` not testable | Use `default=timezone.now` for overridable defaults |
| Sync ORM in async views | Use `sync_to_async` or Django 4.1+ async ORM |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.