Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计通过

django-perf-reviewDjango perf 审查

Agent Skill

用于辅助 Python 项目开发、测试、依赖管理和常见框架工作流。它适合让 Agent 阅读 Python 代码、定位测试问题、整理运行命令、生成脚本或分析数据处理逻辑。使用时需要确认项目虚拟环境、依赖版本和测试入口;涉及执行脚本、读写文件、访问数据库或调用外部 API 时,应先明确运行目录和输入输出范围,避免误改生产数据。

总安装

16,584

周安装

698

GitHub Stars

648

下载量

5,807
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:django-perf-review(Django perf 审查)
来源仓库:https://github.com/getsentry/skills
仓库路径:skills/django-perf-review
安装命令:
npx skills add https://github.com/getsentry/skills --skill django-perf-review
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/getsentry/skills --skill django-perf-review

简介

Django 代码性能审查工具,识别可验证的性能瓶颈。

  • 基于数据流追踪和现有优化检查,避免模式匹配误报。
  • 重点关注数据库查询、缓存策略和响应时间影响。
  • 安装方式:github,通过 npx skills add 命令添加。
  • 适用于性能敏感型应用和线上问题排查。django-perf-review 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Django Performance Review

Review Django code for validated performance issues. Research the codebase to confirm issues before reporting. Report only what you can prove.

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.

PriorityCategoryImpact
1N+1 QueriesCRITICAL - Multiplies with data, causes timeouts
2Unbounded QuerysetsCRITICAL - Memory exhaustion, OOM kills
3Missing IndexesHIGH - Full table scans on large tables
4Write LoopsHIGH - Lock contention, slow requests
5Inefficient PatternsLOW - Rarely worth reporting

Priority 1: N+1 Queries (CRITICAL)

Impact: Each N+1 adds O(n) database round trips. 100 rows = 100 extra queries. 10,000 rows = timeout.

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 annotate

Validation 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 = 25

Rule: 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)
    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)

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()

Usually skip - difference is <1ms in most cases.

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. Verify data volume - Check if table is actually large
  4. Confirm hot path - Trace call sites, verify this runs frequently
  5. Rule out mitigations - Check for caching, rate limiting

If you cannot validate all steps, do not report.


Output Format

## Django Performance Review: [File/Component Name]

### Summary
Validated issues: X (Y Critical, Z High)

### Findings

#### [PERF-001] N+1 Query in UserListView (CRITICAL)
**Location:** `views.py:45`

**Issue:** Related field `profile` accessed in template loop without prefetch.

**Validation:**
- Traced: UserListView → users queryset → user_list.html → `{{ user.profile.bio }}` in loop
- Searched codebase: no select_related('profile') found
- User table: 50k+ rows (verified in admin)
- Hot path: linked from homepage navigation

**Evidence:**

def get_queryset(self): return User.objects.filter(active=True) # no select_related


**Fix:**

def get_queryset(self): return User.objects.filter(active=True).select_related('profile')

If no issues found: "No performance issues identified after reviewing [files] and validating [what you checked]."

Before submitting, sanity check each finding:

  • Does the severity match the actual impact? ("Minor inefficiency" ≠ CRITICAL)
  • Is this a real performance issue or just a style preference?
  • Would fixing this measurably improve performance?

If the answer to any is "no" - remove the finding.


What NOT to Report

  • Test files
  • Admin-only views
  • Management commands
  • Migration files
  • One-time scripts
  • Code behind disabled feature flags
  • Tables with <1000 rows that won't grow
  • Patterns in cold paths (rarely executed code)
  • Micro-optimizations (exists vs count, only/defer without evidence)

False Positives to Avoid

Queryset variable assignment is not an issue:

# This is FINE - no performance difference
projects_qs = Project.objects.filter(org=org)
projects = list(projects_qs)

# vs this - identical performance
projects = list(Project.objects.filter(org=org))

Querysets are lazy. Assigning to a variable doesn't execute anything.

Single query patterns are not N+1:

# This is ONE query, not N+1
projects = list(Project.objects.filter(org=org))

N+1 requires a loop that triggers additional queries. A single list() call is fine.

Missing select_related on single object fetch is not N+1:

# This is 2 queries, not N+1 - report as LOW at most
state = AutofixState.objects.filter(pr_id=pr_id).first()
project_id = state.request.project_id  # second query

N+1 requires a loop. A single object doing 2 queries instead of 1 can be reported as LOW if relevant, but never as CRITICAL/HIGH.

Style preferences are not performance issues: If your only suggestion is "combine these two lines" or "rename this variable" - that's style, not performance. Don't report it.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.6%
按下载量换算2,125

Claude

27.36%
按下载量换算1,589

Cursor

17.85%
按下载量换算1,037

Gemini CLI

8.6%
按下载量换算499

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills