Web Commerce - Middleware

Location: api/nextango/apps/web_commerce/middleware.py Last Updated: 2026-07-08

Overview

CartValidationMiddleware runs on every request to keep request.session['cart_id'] pointed at a cart the current session actually owns, clearing or claiming it before any view runs. It is registered in MIDDLEWARE after the session middleware (settings/base.py:170) and runs in both DEBUG and production.


CartValidationMiddleware

Source: middleware.py:10-79

Identity resolution

The middleware resolves identity via SessionService.resolve_web_session() (cookie-only: the valid, unexpired WebSession for the current Django session_key), not the session-stored storefront_session_id, which could be stale, expired, or point at a foreign session. If no valid WebSession resolves, cart_id is cleared from the session immediately and processing stops.

Validation logic

When request.session['cart_id'] is set and a WebSession resolves:

  1. Cart does not exist: clear cart_id from the session (logged at WARNING).
  2. Cart's web_session_id is None (a legacy cart whose FK was never backfilled, named by this session): claim it atomically onto the resolved web_session via a conditional UPDATE guarded by web_session__isnull=True, status=ACTIVE, so exactly one concurrent request wins the claim and a non-ACTIVE cart is never claimed. If the claim fails (already claimed by a concurrent request, or the cart is not ACTIVE), cart_id is cleared (logged at INFO).
  3. Cart is owned by a different web_session: clear cart_id from the session (logged at WARNING). The pointer is never reassigned to a different owner.
  4. Cart status is not ACTIVE: clear cart_id from the session (logged at INFO).

If none of the above trigger, the session's cart_id is left untouched.

Why this exists

Cart references can become orphaned: the cart was deleted, the session's identity changed across login/logout, the cart completed checkout and is no longer ACTIVE, or a legacy cart predates the web_session FK backfill. Rather than let a downstream view fail with an ownership error, the middleware normalizes request.session['cart_id'] before the view runs so views can rely on it (or on the ownership-based authorization in views.py, which re-checks independently) without repeating this logic.


  • Models: CheckoutSession, CheckoutReservationContext
  • Transactions Models: Cart and its web_session FK
  • Services: SessionService, CartService
  • Views: cart API endpoints and their ownership-based authorization

Was this page helpful?