Split CartItemView so swagger stops showing broken cart endpoints

CartItemView was registered on both /cart/items/ and
/cart/items/{item_uuid}/, so swagger listed POST/PATCH/DELETE on both
paths even though 3 of those 6 combinations raised a TypeError at
runtime (missing/unexpected item_uuid). Split into CartItemView (POST,
list path) and CartItemDetailView (PATCH/DELETE, detail path).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Ali Asadi 2026-08-31 12:01:38 +03:30
parent eb5eb38665
commit d4254ac086
3 changed files with 13 additions and 2 deletions

View file

@ -5,6 +5,7 @@
### Fixed
- `GET /api/v1/stores/` — documented the `category`, `neighborhood`, `search`, `lat`, and `lng` query params for drf-spectacular so they render in swagger. The filtering itself already worked; only the OpenAPI schema was missing them (`apps/stores/views.py`).
- `GET /api/v1/products/` — same issue: documented the existing `store`, `category`, and `search` query params for swagger (`apps/catalog/views.py`).
- Cart items: `CartItemView` was registered on both `/api/v1/cart/items/` and `/api/v1/cart/items/{item_uuid}/`, so swagger showed POST/PATCH/DELETE on both paths — 3 of those 6 combinations crashed with a `TypeError` at runtime (`item_uuid` missing or unexpected). Split into `CartItemView` (POST only, list path) and `CartItemDetailView` (PATCH/DELETE only, detail path) so swagger only shows the combinations that actually work (`apps/orders/views.py`, `apps/orders/urls.py`).
### Added
- `GET /api/v1/cities/?search=` — search cities by name (`apps/locations/views.py`); previously no text search existed.

View file

@ -2,6 +2,7 @@ from django.urls import path
from rest_framework.routers import DefaultRouter
from .views import (
CartItemDetailView,
CartItemView,
CartView,
CheckoutView,
@ -23,5 +24,5 @@ urlpatterns = router.urls + [
path('checkout/', CheckoutView.as_view(), name='checkout'),
path('cart/', CartView.as_view(), name='cart'),
path('cart/items/', CartItemView.as_view(), name='cart-items'),
path('cart/items/<uuid:item_uuid>/', CartItemView.as_view(), name='cart-item-detail'),
path('cart/items/<uuid:item_uuid>/', CartItemDetailView.as_view(), name='cart-item-detail'),
]

View file

@ -47,7 +47,7 @@ class CartView(APIView):
class CartItemView(APIView):
"""Add/update/remove a single product line in the authenticated user's cart."""
"""Add a product line to the authenticated user's cart."""
schema_tags = ['Cart']
serializer_class = CartItemWriteSerializer
@ -73,6 +73,15 @@ class CartItemView(APIView):
return Response(CartItemSerializer(item).data, status=status.HTTP_201_CREATED)
class CartItemDetailView(APIView):
"""Update/remove a single product line in the authenticated user's cart."""
schema_tags = ['Cart']
serializer_class = CartItemWriteSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {}
@extend_schema(responses=CartItemSerializer)
def patch(self, request, item_uuid):
item = get_object_or_404(CartItem, uuid=item_uuid, cart__user=request.user)