返回 Skill 列表
extension
分类: 开发与工程无需 API Key

django-simplifier

简化过于复杂的Django代码并检测Django特有的反模式。当用户要求简化、重构或改进Django代码时使用,查找N+1查询问题,检测Django反模式,优化QuerySets,或者分析Django项目架构。触发条件涉及Django模型、视图、QuerySets、ORM优化、序列化器、表单、信号、中间件或Django最佳实践。对于一般的Python分析,请使用python-simplifier技能。

person作者: jakexiaohubgithub

Django Code Simplifier

Transform complex Django code into clean, performant, idiomatic solutions.

Analysis Scripts

# Comprehensive Django analysis (runs all Django checks)
python scripts/analyze_django.py /path/to/project

# Individual analyzers:
python scripts/find_django_issues.py .           # N+1 queries, fat views, basic issues
python scripts/find_django_antipatterns.py .     # ORM misuse, security issues, model problems
python scripts/find_django_overengineering.py .  # Unnecessary abstractions, premature patterns

# Filter by category or severity:
python scripts/find_django_antipatterns.py . --category performance
python scripts/find_django_antipatterns.py . --category security
python scripts/find_django_antipatterns.py . --min-severity medium

# JSON output for CI/tooling
python scripts/analyze_django.py . --format json > report.json

What Each Script Detects

find_django_issues.py - Basic Issues

  • N+1 query risks (.all() in loops)
  • .save() / .delete() / .create() in loops
  • Fat views (100+ lines)
  • Hardcoded URLs instead of reverse()
  • Missing select_related / prefetch_related

find_django_antipatterns.py - Comprehensive Anti-Patterns

| Category | Issues Detected | |----------|-----------------| | query | save_in_loop, create_in_loop, unbounded_queryset, update_without_f, raw_sql, deprecated_extra | | performance | excessive_queries, nested template loops, template queries | | model | missing_str_method, fat_model, too_many_fields | | view | hardcoded_url, fat_view_method, url_without_name | | form | query_in_form_clean | | security | hardcoded_secret, debug_true, mark_safe_usage, eval_exec_usage |

find_django_overengineering.py - Over-Engineering

| Issue | Description | |-------|-------------| | single_impl_abstract_model | Abstract model with only one concrete child | | unused_abstract_model | Abstract model never extended | | unnecessary_manager | Custom manager with ≤1 method | | unnecessary_signal | Signal for simple save logic | | single_use_mixin | Mixin used only once | | deep_form_inheritance | Form/Serializer with 3+ inheritance levels | | unnecessary_middleware | Middleware with minimal logic | | unnecessary_service_layer | Service wrapping simple CRUD |

Common Django Patterns

N+1 Query Prevention

# Before: N+1 problem
for order in Order.objects.all():
    print(order.customer.name)  # Query per iteration!

# After: select_related (ForeignKey/OneToOne)
for order in Order.objects.select_related('customer'):
    print(order.customer.name)  # Single query

# After: prefetch_related (ManyToMany/reverse FK)
for customer in Customer.objects.prefetch_related('orders'):
    print(customer.orders.count())

Bulk Operations

# Before: Loop creates (N queries)
for data in items:
    Model.objects.create(**data)

# After: bulk_create (1 query)
Model.objects.bulk_create([Model(**d) for d in items])

# Before: Loop updates
for obj in queryset:
    obj.status = 'done'
    obj.save()

# After: Single update
queryset.update(status='done')

# With F() for safe increment
from django.db.models import F
Product.objects.filter(id=1).update(stock=F('stock') - 1)

Fat View → Thin View

# Before: Business logic in view
def order_view(request, order_id):
    order = Order.objects.get(id=order_id)
    # 50 lines of business logic...
    return render(...)

# After: Logic in model/service
def order_view(request, order_id):
    order = get_object_or_404(Order, id=order_id)
    result = order.process()  # Logic moved to model
    return render(request, 'order.html', {'result': result})

Signals → Explicit Methods

# Before: Hidden signal
@receiver(post_save, sender=Order)
def update_inventory(sender, instance, **kwargs):
    # Hard to trace, implicit behavior
    ...

# After: Explicit method
class Order(models.Model):
    def complete(self):
        self.status = 'completed'
        self.save()
        self._update_inventory()  # Explicit, traceable

URL Best Practices

# Before: Hardcoded
return redirect('/orders/123/')

# After: Named URL
from django.urls import reverse
return redirect(reverse('order-detail', args=[123]))

# Or with shortcut
from django.shortcuts import redirect
return redirect('order-detail', pk=123)

Model Best Practices

class Order(models.Model):
    # Always add __str__
    def __str__(self):
        return f"Order #{self.number}"
    
    # Use TextChoices
    class Status(models.TextChoices):
        PENDING = 'pending', 'Pending'
        COMPLETED = 'completed', 'Completed'
    
    status = models.CharField(max_length=20, choices=Status.choices)
    
    # Don't use null=True on CharField
    # BAD: name = models.CharField(null=True, blank=True)
    # GOOD:
    name = models.CharField(blank=True, default='')
    
    # Always set related_name
    customer = models.ForeignKey(Customer, related_name='orders', on_delete=models.CASCADE)
    
    class Meta:
        ordering = ['-created_at']
        indexes = [models.Index(fields=['status', 'created_at'])]

Django Over-Engineering Signs

| Pattern | Problem | Solution | |---------|---------|----------| | Abstract model with 1 child | Premature abstraction | Merge into concrete model | | CBV with 6+ overrides | Too complex | Use function-based view | | Single-use mixin | No reuse benefit | Inline the code | | Many signal handlers | Hard to trace | Use explicit method calls | | Custom manager for simple filter | Unnecessary | Use QuerySet methods | | Service layer for CRUD | Extra indirection | Use model methods |

Security Checklist

# Use get_object_or_404 with ownership check
order = get_object_or_404(Order, id=id, owner=request.user)

# Never use mark_safe with user data
# BAD: mark_safe(user_input)
# GOOD:
from django.utils.html import format_html
format_html('<p>{}</p>', user_input)

# Keep secrets out of code
# BAD: SECRET_KEY = 'hardcoded-secret'
# GOOD: SECRET_KEY = os.environ.get('SECRET_KEY')

When to Use What

| Need | Use | |------|-----| | Simple CRUD | Generic views, ModelForm | | Complex business logic | Model methods | | Cross-cutting concerns | Middleware (sparingly) | | Decoupled apps | Signals (sparingly) | | Query optimization | select_related, prefetch_related | | Bulk operations | bulk_create, bulk_update, update() |