Skip to main content

Overview

This E-commerce API is built with Django and Django REST Framework, following a modular app-based architecture that separates concerns and promotes code reusability.

Django App Structure

The API is organized into multiple Django applications, each handling a specific domain:

Catalogue

Product management including categories, variants, attributes, media, and reviews

Orders

Order processing and order item management

Customers

Customer accounts, authentication, and address management

Cart

Shopping cart functionality and item management

Discount

Promotional offers, vouchers, and discount conditions

Payments

Payment processing with Braintree integration

Stores

Multi-vendor store management

Wishlist

Customer wishlists and saved items

App Location

All apps are located in ~/workspace/source/ directory:
source/
├── catalogue/      # Product catalog management
├── orders/         # Order processing
├── customers/      # Customer accounts
├── cart/           # Shopping cart
├── discount/       # Offers and vouchers
├── payments/       # Payment processing
├── stores/         # Store management
├── vendors/        # Vendor management
├── wishlist/       # Wishlists
└── config/         # Project configuration

API Versioning

The API uses URL path versioning with the current version being v1.

Base URL Structure

http://your-domain.com/api/v1/{endpoint}

Example Endpoints

GET /api/v1/products/
All endpoints shown in this documentation are relative to the /api/v1/ base path.

URL Configuration

Versioning is configured in config/urls.py:63:
path("api/v1/", include(urls)),

Key Architectural Patterns

Abstract Base Models

The API uses abstract base models to share common functionality across apps. Located in catalogue/abstract.py, these models provide:

Timestamp Model

class Timestamp(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
Automatically tracks creation and modification times for all models.

BaseModel

class BaseModel(Timestamp):
    is_active = models.BooleanField(default=True)
    
    objects = models.Manager()
    active_objects = ActiveObjectsManager()
Features:
  • Inherits timestamp tracking
  • Soft delete support via is_active flag
  • Dual managers: objects (all records) and active_objects (active only)
Used by: Product, ProductVariant, ProductMedia, Review, Order, OrderItem, Offer

TimeBased Model

class TimeBased(BaseModel):
    valid_from = models.DateTimeField()
    valid_to = models.DateTimeField()
Features:
  • Extends BaseModel with time-based validity
  • Automatic validation ensuring valid_to > valid_from
Used by: Offer, Voucher

Manager Classes

Custom managers provide filtered querysets for common use cases:

ActiveObjectsManager

class ActiveObjectsManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_active=True)
Automatically filters out soft-deleted records. Usage Example:
# Get all active products
Product.active_objects.all()

# Get all products (including inactive)
Product.objects.all()

ActiveOfferManager

class ActiveOfferManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(
            valid_from__lte=datetime.now(timezone.utc),
            valid_to__gt=datetime.now(timezone.utc),
            is_active=True,
        )
Filters offers and vouchers to only those currently valid. Usage Example:
# Get currently valid offers
Offer.active_objects.all()

# Get currently valid vouchers
Voucher.active_objects.all()

Authentication

The API supports multiple authentication methods configured in config/settings.py:167-174:

Permission System

Default permission requires authentication:
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated'
    ],
}
Individual views can override this:
class ProductListView(GenericAPIView):
    permission_classes = [AllowAny]  # Public access

Database Configuration

Supports both PostgreSQL (production) and SQLite (development):
DATABASES = {
    'PG_DB': {
        'ENGINE': 'django.db.backends.postgresql',
        # ... PostgreSQL config
    },
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite'
    }
}

Custom User Model

Uses email-based authentication instead of username:
AUTH_USER_MODEL = 'customers.Customer'

class Customer(AbstractUser):
    email = models.EmailField(unique=True, db_index=True)
    username = None
    
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["first_name", "last_name"]

Design Principles

Each Django app handles a specific domain with clear boundaries. For example, catalogue manages products, while orders handles order processing.
Abstract base models and managers are shared across apps, reducing code duplication and ensuring consistent behavior.
Records are marked inactive rather than deleted, preserving data integrity and audit trails.
Strategic indexes on frequently queried fields improve performance:
  • Product: category, is_available
  • Order: customer, status, created
  • Offer: valid_from, valid_to, store
Store foreign keys enable multi-vendor marketplace functionality.

Next Steps

Data Models

Explore the core data models and their relationships

Filtering & Pagination

Learn how to filter, search, and paginate API results

Build docs developers (and LLMs) love