--- name: django-reviewer description: | WHEN: Django project review, ORM queries, views/templates, admin customization WHAT: ORM optimization + View patterns + Template security + Admin config + Migration safety WHEN NOT: FastAPI → fastapi-reviewer, Flask → flask-reviewer, DRF API only → consider api-expert --- # 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 | Check | Recommendation | Severity | |-------|----------------|----------| | N+1 query | Use select_related/prefetch_related | CRITICAL | | .all() in template | Prefetch in view | HIGH | | filter().first() | Use .filter().first() or get_or_none | LOW | | Multiple .save() | Use bulk_update/bulk_create | MEDIUM | ```python # 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 | Check | Recommendation | Severity | |-------|----------------|----------| | Function view for CRUD | Use Class-Based Views | LOW | | No permission check | Add @login_required or PermissionMixin | HIGH | | Business logic in view | Move to service/manager | MEDIUM | | No pagination | Add Paginator | MEDIUM | ```python # 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 | Check | Recommendation | Severity | |-------|----------------|----------| | \|safe filter misuse | Only use for trusted content | CRITICAL | | {% autoescape off %} | Avoid, use mark_safe in Python | HIGH | | User input in JS | Use json_script filter | HIGH | | No CSRF token | Add {% csrf_token %} | CRITICAL | ```html