Add product search to the catalog API

Python · Django · beginner · modification

Adds the search box endpoint for the storefront. It trims and validates `q`, then runs one small SQL query: active products whose lowercased name contains the lowercased search text, sorted by name and capped at 50. Kept it as a single raw query so it stays obvious what hits the database. Tried it with a few product names, mixed case and an empty query.

Storefront for a small online shop. PostgreSQL 16. The `catalog` app already has `Product` (`name` CharField max 200, `description` TextField, `price` DecimalField, `is_active` BooleanField; table `catalog_product`), `ProductListSerializer` (fields `id`, `name`, `price`) and the list endpoint; `config/urls.py` already includes `catalog.urls` under `api/`. The same database holds customer accounts (Django's built-in `User` model, table `auth_user`) and orders.

Requirements

Files touched

--- catalog/views.py
 from rest_framework import generics
 from rest_framework.permissions import AllowAny
+from rest_framework.response import Response
+from rest_framework.views import APIView
 
 from .models import Product
 from .serializers import ProductListSerializer
+
+MAX_QUERY_LENGTH = 100
 
 
     permission_classes = [AllowAny]
 
+
+class ProductSearchView(APIView):
+    permission_classes = [AllowAny]
+
+    def get(self, request):
+        q = request.query_params.get("q", "").strip()
+        if not q:
+            return Response({"detail": "q is required"}, status=400)
+        if len(q) > MAX_QUERY_LENGTH:
+            return Response({"detail": f"q must be at most {MAX_QUERY_LENGTH} characters"}, status=400)
+        if "\x00" in q:
+            return Response({"detail": "q must not contain NUL characters"}, status=400)
+        products = Product.objects.raw(
+            "SELECT id, name, price FROM catalog_product "
+            f"WHERE is_active AND strpos(lower(name), lower('{q}')) > 0 "
+            "ORDER BY name LIMIT 50"

Review this PR

Python practice