From claude-initial-setup
Master Django ORM patterns: QuerySets, select_related, prefetch_related, F/Q objects, annotations, aggregations, and raw SQL safety. Use when the user writes Django database queries, asks about ORM optimization, encounters N+1 queries, or works with complex filtering and aggregation. Trigger when you see inefficient Django queries.
npx claudepluginhub versoxbt/claude-initial-setup --plugin claude-initial-setupThis skill uses the workspace's default tool permissions.
Write efficient, expressive Django ORM queries. The ORM is lazy by default -- QuerySets
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Write efficient, expressive Django ORM queries. The ORM is lazy by default -- QuerySets are not evaluated until iterated. Understanding this is key to avoiding N+1 queries and building performant applications.
QuerySets are lazy -- they build SQL without executing until evaluated. Chain freely.
# Lazy -- no SQL executed yet
qs = (
Article.objects
.filter(status="published")
.exclude(category__name="draft")
.order_by("-published_at")
)
# SQL executes when you iterate, slice, call list(), len(), bool(), etc.
articles = list(qs[:10])
# Efficient existence check -- use .exists() not len() or bool()
if Article.objects.filter(slug=slug).exists():
raise ValidationError("Slug already taken")
# Efficient count -- use .count() not len(qs)
total = Article.objects.filter(status="published").count()
# Get or 404
from django.shortcuts import get_object_or_404
article = get_object_or_404(Article, slug=slug, status="published")
Performs a SQL JOIN. Use for ForeignKey and OneToOneField relationships. Fetches related objects in a single query.
# WITHOUT select_related -- N+1 problem
articles = Article.objects.all()
for article in articles:
print(article.author.name) # Each access hits the database
# WITH select_related -- single JOIN query
articles = Article.objects.select_related("author", "category").all()
for article in articles:
print(article.author.name) # No extra query -- already loaded
# Chain through relationships
comments = (
Comment.objects
.select_related("article__author", "article__category")
.filter(is_approved=True)
)
Performs a separate query and joins in Python. Use for ManyToManyField and reverse ForeignKey relationships.
from django.db.models import Prefetch
# Basic prefetch -- separate query for tags
articles = Article.objects.prefetch_related("tags").all()
# Custom Prefetch with filtering
articles = Article.objects.prefetch_related(
Prefetch(
"comments",
queryset=Comment.objects.filter(is_approved=True).select_related("author"),
to_attr="approved_comments", # Access as article.approved_comments
)
)
for article in articles:
for comment in article.approved_comments: # No extra queries
print(f"{comment.author.name}: {comment.text}")
Use F() to reference field values in queries without pulling data into Python.
from django.db.models import F
# Increment without race condition
Article.objects.filter(id=article_id).update(view_count=F("view_count") + 1)
# Compare fields
products = Product.objects.filter(stock__lt=F("reorder_level"))
# Arithmetic between fields
orders = Order.objects.annotate(
profit=F("revenue") - F("cost")
).filter(profit__gt=0)
# Reference related fields
articles = Article.objects.filter(
comments_count__gt=F("category__avg_comments") * 2
)
Use Q() for OR conditions, negation, and complex boolean logic.
from django.db.models import Q
# OR condition
results = Article.objects.filter(
Q(status="published") | Q(author=current_user)
)
# AND with OR
results = Article.objects.filter(
Q(status="published") & (Q(category="tech") | Q(category="science"))
)
# Negation
results = Article.objects.filter(~Q(status="archived"))
# Dynamic query building
filters = Q()
if search_term:
filters &= Q(title__icontains=search_term) | Q(body__icontains=search_term)
if category:
filters &= Q(category__slug=category)
if date_from:
filters &= Q(published_at__gte=date_from)
articles = Article.objects.filter(filters)
Push computation to the database instead of doing it in Python.
from django.db.models import Count, Avg, Sum, Max, Min, Value, CharField
from django.db.models.functions import Coalesce, Upper, TruncMonth
# Aggregate -- returns a dict
stats = Order.objects.aggregate(
total_revenue=Sum("amount"),
avg_order=Avg("amount"),
order_count=Count("id"),
max_order=Max("amount"),
)
# Annotate -- adds computed fields to each object in QuerySet
authors = (
User.objects
.annotate(
article_count=Count("articles"),
avg_rating=Avg("articles__rating"),
total_views=Sum("articles__view_count"),
)
.filter(article_count__gt=5)
.order_by("-total_views")
)
# Conditional aggregation
from django.db.models import Case, When, IntegerField
articles = Article.objects.annotate(
engagement_score=Case(
When(view_count__gt=1000, then=Value(3)),
When(view_count__gt=100, then=Value(2)),
default=Value(1),
output_field=IntegerField(),
)
)
# Group by month
monthly_revenue = (
Order.objects
.annotate(month=TruncMonth("created_at"))
.values("month")
.annotate(
revenue=Sum("amount"),
count=Count("id"),
)
.order_by("month")
)
Use parameterized queries to prevent SQL injection. Never interpolate user input.
# Safe raw query with parameters
users = User.objects.raw(
"SELECT * FROM auth_user WHERE email LIKE %s AND is_active = %s",
[f"%@{domain}", True],
)
# Raw SQL for complex queries that don't map to a model
from django.db import connection
def get_revenue_report(year: int) -> list[dict]:
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT category, SUM(amount) as total, COUNT(*) as count
FROM orders_order
WHERE EXTRACT(YEAR FROM created_at) = %s
GROUP BY category
ORDER BY total DESC
""",
[year],
)
columns = [col[0] for col in cursor.description]
return [dict(zip(columns, row)) for row in cursor.fetchall()]
select_related or
prefetch_related. Use django-debug-toolbar to spot these.[a for a in articles if a.status == "published"]
instead of .filter(status="published"). Let the database do the filtering.len(qs): Use .count() which executes SELECT COUNT(*) instead
of fetching all rows.f"WHERE id = {user_id}" is a SQL injection
vulnerability. Always use parameterized queries with %s placeholders..all() before .filter(): .filter() already returns a new QuerySet.
Article.objects.filter(...) is cleaner than Article.objects.all().filter(...).| Operation | Method |
|---|---|
| FK/OneToOne join | .select_related("field") |
| M2M/Reverse FK | .prefetch_related("field") |
| OR conditions | Q(a=1) | Q(b=2) |
| Database-level field ref | F("field_name") |
| Aggregate (single result) | .aggregate(total=Sum("field")) |
| Annotate (per-row) | .annotate(count=Count("rel")) |
| Conditional | Case(When(cond, then=val)) |
| Existence check | .exists() |
| Efficient count | .count() |
| Bulk create | .bulk_create([obj1, obj2]) |
| Bulk update | .bulk_update(objs, ["field"]) |