Claude-skill-registry django-reviewer

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/django-reviewer" ~/.claude/skills/majiayu000-claude-skill-registry-django-reviewer && rm -rf "$T"
manifest: skills/data/django-reviewer/SKILL.md
source content

Django Reviewer Skill

Purpose

Reviews Django projects for ORM usage, view patterns, security, and best practices.

When to Use

  • Django project code review
  • ORM query optimization
  • View/template review
  • Admin customization review
  • Migration safety check

Project Detection

  • django
    in requirements.txt/pyproject.toml
  • manage.py
    in project root
  • settings.py
    with INSTALLED_APPS
  • urls.py
    ,
    views.py
    ,
    models.py
    files

Workflow

Step 1: Analyze Project

**Django**: 4.2+ / 5.0+
**Database**: PostgreSQL/MySQL/SQLite
**Template Engine**: Django Templates/Jinja2
**REST**: Django REST Framework
**Admin**: Django Admin / Unfold

Step 2: Select Review Areas

AskUserQuestion:

"Which areas to review?"
Options:
- Full Django review (recommended)
- ORM and query optimization
- Views and URL patterns
- Templates and security
- Admin customization
multiSelect: true

Detection Rules

ORM Optimization

CheckRecommendationSeverity
N+1 queryUse select_related/prefetch_relatedCRITICAL
.all() in templatePrefetch in viewHIGH
filter().first()Use .filter().first() or get_or_noneLOW
Multiple .save()Use bulk_update/bulk_createMEDIUM
# BAD: N+1 query
def get_orders(request):
    orders = Order.objects.all()
    # Each order.customer triggers a query!
    return render(request, "orders.html", {"orders": orders})

# GOOD: select_related for ForeignKey
def get_orders(request):
    orders = Order.objects.select_related("customer").all()
    return render(request, "orders.html", {"orders": orders})

# GOOD: prefetch_related for ManyToMany/reverse FK
def get_orders(request):
    orders = Order.objects.prefetch_related("items").all()
    return render(request, "orders.html", {"orders": orders})

# BAD: Multiple saves
for item in items:
    item.status = "processed"
    item.save()

# GOOD: Bulk update
Item.objects.filter(id__in=item_ids).update(status="processed")

View Patterns

CheckRecommendationSeverity
Function view for CRUDUse Class-Based ViewsLOW
No permission checkAdd @login_required or PermissionMixinHIGH
Business logic in viewMove to service/managerMEDIUM
No paginationAdd PaginatorMEDIUM
# BAD: Logic in view
def create_order(request):
    if request.method == "POST":
        # Too much logic here
        user = request.user
        cart = Cart.objects.get(user=user)
        order = Order.objects.create(user=user, total=cart.total)
        for item in cart.items.all():
            OrderItem.objects.create(order=order, product=item.product)
        cart.items.all().delete()
        send_confirmation_email(user, order)
        return redirect("order_detail", order.id)

# GOOD: Service layer
# services/order_service.py
class OrderService:
    @staticmethod
    def create_from_cart(user: User) -> Order:
        cart = Cart.objects.get(user=user)
        order = Order.objects.create(user=user, total=cart.total)
        OrderItem.objects.bulk_create([
            OrderItem(order=order, product=item.product)
            for item in cart.items.all()
        ])
        cart.items.all().delete()
        send_confirmation_email.delay(user.id, order.id)  # Celery task
        return order

# views.py
class CreateOrderView(LoginRequiredMixin, View):
    def post(self, request):
        order = OrderService.create_from_cart(request.user)
        return redirect("order_detail", order.id)

Template Security

CheckRecommendationSeverity
|safe filter misuseOnly use for trusted contentCRITICAL
{% autoescape off %}Avoid, use mark_safe in PythonHIGH
User input in JSUse json_script filterHIGH
No CSRF tokenAdd {% csrf_token %}CRITICAL
<!-- BAD: XSS vulnerability -->
<div>{{ user_content|safe }}</div>

<!-- GOOD: Auto-escaped (default) -->
<div>{{ user_content }}</div>

<!-- BAD: User data in JS -->
<script>
var data = "{{ user_data }}";  // XSS risk!
</script>

<!-- GOOD: json_script filter -->
{{ user_data|json_script:"user-data" }}
<script>
const data = JSON.parse(
    document.getElementById("user-data").textContent
);
</script>

Model Design

CheckRecommendationSeverity
No indexes on filter fieldsAdd db_index=TrueHIGH
CharField without max_lengthAlways specify max_lengthMEDIUM
No str methodAdd for admin displayLOW
No Meta orderingAdd default orderingLOW
# GOOD: Well-designed model
class Order(models.Model):
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="orders",
    )
    status = models.CharField(
        max_length=20,
        choices=OrderStatus.choices,
        default=OrderStatus.PENDING,
        db_index=True,  # Frequently filtered
    )
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["user", "status"]),
        ]

    def __str__(self):
        return f"Order {self.id} - {self.user.email}"

Migration Safety

CheckRecommendationSeverity
Non-nullable field without defaultAdd default or null=True firstCRITICAL
Large table ALTERUse RunSQL with concurrent indexHIGH
Data migration in schema migrationSeparate into data migrationMEDIUM
# BAD: Adding non-nullable field
class Migration(migrations.Migration):
    operations = [
        migrations.AddField(
            model_name="order",
            name="tracking_number",
            field=models.CharField(max_length=100),  # Will fail!
        ),
    ]

# GOOD: Safe migration strategy
# Step 1: Add nullable field
migrations.AddField(
    model_name="order",
    name="tracking_number",
    field=models.CharField(max_length=100, null=True),
),
# Step 2: Data migration to populate
# Step 3: Make non-nullable with default

Response Template

## Django Code Review Results

**Project**: [name]
**Django**: 5.0 | **DB**: PostgreSQL | **DRF**: 3.14

### ORM Optimization
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | views.py:45 | N+1 query - missing select_related |

### View Patterns
| Status | File | Issue |
|--------|------|-------|
| HIGH | views.py:23 | Missing LoginRequiredMixin |

### Template Security
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | templates/user.html:12 | Unsafe |safe filter usage |

### Migrations
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | 0015_add_field.py | Non-nullable field without default |

### Recommended Actions
1. [ ] Add select_related to order queries
2. [ ] Add permission mixins to views
3. [ ] Remove |safe from user content
4. [ ] Fix migration for tracking_number field

Best Practices

  1. ORM: Always prefetch related objects
  2. Views: Use CBV, service layer for logic
  3. Security: CSRF, XSS prevention, permissions
  4. Migrations: Zero-downtime strategies
  5. Testing: Factory Boy, pytest-django

Integration

  • python-reviewer
    : General Python patterns
  • security-scanner
    : Django security audit
  • sql-optimizer
    : Query analysis