django-perf-review – skill Lập trình cho agent AI
Review hiệu năng code Django. Dùng khi được yêu cầu "review Django performance", "tìm N+1 query", "tối ưu Django", "kiểm tra queryset performance", "database performance", "vấn đề Django ORM", hoặc audit code Django về các vấn đề hiệu năng.
Cài skill django-perf-review bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/django-perf-review-ea391.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /django-perf-review – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/django-perf-review-ea391.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $django-perf-review – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/django-perf-review-ea391.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /django-perf-review – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/django-perf-review-ea391.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /django-perf-review – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
Django Performance Review
Review Django code for validated performance issues. Research the codebase to confirm issues before reporting. Report only what you can prove.
When to Use
- You need a Django performance review focused on verified ORM and query issues.
- The code likely has N+1 queries, unbounded querysets, missing indexes, or other database-driven bottlenecks.
- You want only provable performance findings, not speculative optimization advice.
Review Approach
1. Research first - Trace data flow, check for existing optimizations, verify data volume
2. Validate before reporting - Pattern matching is not validation
3. Zero findings is acceptable - Don't manufacture issues to appear thorough
4. Severity must match impact - If you catch yourself writing "minor" in a CRITICAL finding, it's not critical. Downgrade or skip it.
Impact Categories
Issues are organized by impact. Focus on CRITICAL and HIGH - these cause real problems at scale.
| Priority | Category | Impact |
|----------|----------|--------|
| 1 | N+1 Queries | CRITICAL - Multiplies with data, causes timeouts |
| 2 | Unbounded Querysets | CRITICAL - Memory exhaustion, OOM kills |
| 3 | Missing Indexes | HIGH - Full table scans on large tables |
| 4 | Write Loops | HIGH - Lock contention, slow requests |
| 5 | Inefficient Patterns | LOW - Rarely worth reporting |
---
Priority 1: N+1 Queries (CRITICAL)
Impact: N+1 adds database round trips proportional to evaluated rows; latency and severity require actual workload/query measurements, not a universal timeout threshold.
Rule: Prefetch related data accessed in loops
Validate by tracing: View → Queryset → Template/Serializer → Loop access
# PROBLEM: N+1 - each iteration queries profile
def user_list(request):
users = User.objects.all()
return render(request, 'users.html', {'users': users})
# Template:
# {% for user in users %}
# {{ user.profile.bio }} ← triggers query per user
# {% endfor %}
# SOLUTION: Prefetch in view
def user_list(request):
users = User.objects.select_related('profile')
return render(request, 'users.html', {'users': users})Rule: Prefetch in serializers, not just views
DRF serializers accessing related fields cause N+1 if queryset isn't optimized.
# PROBLEM: SerializerMethodField queries per object
class UserSerializer(serializers.ModelSerializer):
order_count = serializers.SerializerMethodField()
def get_order_count(self, obj):
return obj.orders.count() # ← query per user
# SOLUTION: Annotate in viewset, access in serializer
class UserViewSet(viewsets.ModelViewSet):
def get_queryset(self):
return User.objects.annotate(order_count=Count('orders'))
class UserSerializer(serializers.ModelSerializer):
order_count = serializers.IntegerField(read_only=True)Rule: Model properties that query are dangerous in loops
# PROBLEM: Property triggers query when accessed
class User(models.Model):
@property
def recent_orders(self):
return self.orders.filter(created__gte=last_week)[:5]
# Used in template loop = N+1
# SOLUTION: Use Prefetch with custom queryset, or annotateValidation Checklist for N+1
- [ ] Traced data flow from view to template/serializer
- [ ] Confirmed related field is accessed inside a loop
- [ ] Searched codebase for existing select_related/prefetch_related
- [ ] Verified table has significant row count (1000+)
- [ ] Confirmed this is a hot path (not admin, not rare action)
---
Priority 2: Unbounded Querysets (CRITICAL)
Impact: Loading entire tables exhausts memory. Large tables cause OOM kills and worker restarts.
Rule: Always paginate list endpoints
# PROBLEM: No pagination - loads all rows
class UserListView(ListView):
model = User
template_name = 'users.html'
# SOLUTION: Add pagination
class UserListView(ListView):
model = User
template_name = 'users.html'
paginate_by = 25Rule: Use iterator() for large batch processing
# PROBLEM: Loads all objects into memory at once
for user in User.objects.all():
process(user)
# SOLUTION: Stream with iterator()
for user in User.objects.iterator(chunk_size=1000):
process(user)Rule: Never call list() on unbounded querysets
# PROBLEM: Forces full evaluation into memory
all_users = list(User.objects.all())
# SOLUTION: Keep as queryset, slice if needed
users = User.objects.all()[:100]Validation Checklist for Unbounded Querysets
- [ ] Table is large (10k+ rows) or will grow unbounded
- [ ] No pagination class, paginate_by, or slicing
- [ ] This runs on user-facing request (not background job with chunking)
---
Priority 3: Missing Indexes (HIGH)
Impact: Full table scans. Negligible on small tables, catastrophic on large ones.
Rule: Index fields used in WHERE clauses on large tables
# PROBLEM: Filtering on unindexed field
# User.objects.filter(email=email) # full scan if no index
class User(models.Model):
email = models.EmailField() # ← no db_index
# SOLUTION: Add index
class User(models.Model):
email = models.EmailField(db_index=True)Rule: Index fields used in ORDER BY on large tables
# PROBLEM: Sorting requires full scan without index
Order.objects.order_by('-created')
# SOLUTION: Index the sort field
class Order(models.Model):
created = models.DateTimeField(db_index=True)Rule: Use composite indexes for common query patterns
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.CharField(max_length=20)
created = models.DateTimeField()
class Meta:
indexes = [
models.Index(fields=['user', 'status']), # for filter(user=x, status=y)
models.Index(fields=['status', '-created']), # for filter(status=x).order_by('-created')
]Validation Checklist for Missing Indexes
- [ ] Table has 10k+ rows
- [ ] Field is used in filter() or order_by() on hot path
- [ ] Checked model - no db_index=True or Meta.indexes entry
- [ ] Not a foreign key (already indexed automatically)
---
Priority 4: Write Loops (HIGH)
Bulk operations change semantics: verify custom save/delete methods, signals, validation, generated IDs, cascades, transaction boundaries and database limits before replacing loops. QuerySet.delete may run multiple SQL statements and cascade/signals; it is not guaranteed to be a single DELETE. Index decisions require the actual execution plan and workload/selectivity, not field-name matching alone.
Impact: N database writes instead of 1. Lock contention. Slow requests.
Rule: Use bulk_create instead of create() in loops
# PROBLEM: N inserts, N round trips
for item in items:
Model.objects.create(name=item['name'])
# SOLUTION: Single bulk insert
Model.objects.bulk_create([
Model(name=item['name']) for item in items
])Rule: Use update() or bulk_update instead of save() in loops
# PROBLEM: N updates
for obj in queryset:
obj.status = 'done'
obj.save()
# SOLUTION A: Single UPDATE statement (same value for all)
queryset.update(status='done')
# SOLUTION B: bulk_update (different values)
for obj in objects:
obj.status = compute_status(obj)
Model.objects.bulk_update(objects, ['status'], batch_size=500)Rule: Use delete() on queryset, not in loops
# PROBLEM: N deletes
for obj in queryset:
obj.delete()
# SOLUTION: Single DELETE
queryset.delete()Validation Checklist for Write Loops
- [ ] Loop iterates over 100+ items (or unbounded)
- [ ] Each iteration calls create(), save(), or delete()
- [ ] This runs on user-facing request (not one-time migration script)
---
Priority 5: Inefficient Patterns (LOW)
Rarely worth reporting. Include only as minor notes if you're already reporting real issues.
Pattern: count() vs exists()
# Slightly suboptimal
if queryset.count() > 0:
do_thing()
# Marginally better
if queryset.exists():
do_thing()Measure first — runtime depends on database, query shape, cache state and whether the queryset is already evaluated.
Pattern: len(queryset) vs count()
# Fetches all rows to count
if len(queryset) > 0: # bad if queryset not yet evaluated
# Single COUNT query
if queryset.count() > 0:Only flag if queryset is large and not already evaluated.
Pattern: get() in small loops
# N queries, but if N is small (< 20), often fine
for id in ids:
obj = Model.objects.get(id=id)Only flag if loop is large or this is in a very hot path.
---
Validation Requirements
Before reporting ANY issue:
1. Trace the data flow - Follow queryset from creation to consumption
2. Search for existing optimizations - Grep for select_related, prefetch_related, pagination
3. **Ve
… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- django-pro – Thành thạo Django 5.x với async view, DRF, Celery và Django Channels. Xây dựng ứng dụng…
- pr-review-expert – Dùng khi người dùng yêu cầu review pull request, phân tích thay đổi code, kiểm tra vấn…
- sympy – Thực hiện toán ký hiệu chính xác với SymPy cho đại số, giải tích, giải phương trình, đại…
- docs-guard – Rà soát tài liệu được tạo hoặc thay đổi trước khi phát hành, bao gồm README, tham chiếu…
- documentation – Quy trình tạo tài liệu gồm tài liệu API, tài liệu kiến trúc, file README, chú thích code…
- documentation-generation-doc-generate – Bạn là chuyên gia tài liệu, chuyên tạo tài liệu toàn diện, dễ bảo trì từ code. Tạo tài…
- songsee – Phổ tần số và đặc trưng âm thanh (mel, chroma, MFCC) qua CLI.
- documentation-templates – Mẫu tài liệu và hướng dẫn cấu trúc. README, tài liệu API, chú thích code và tài liệu…