Python Django Multi-Vendor E-Commerce Platform

Written by

in

Building a Python Django multi‑vendor e‑commerce platform is no longer a distant dream for developers who want to launch a marketplace like Amazon, Etsy, or eBay. With Django’s batteries‑included philosophy, robust ORM, and thriving third‑party ecosystem, you can create a scalable, secure, and feature‑rich marketplace that lets multiple sellers list products, manage orders, and receive payments—all from a single codebase. In this guide we’ll explore the core architecture, essential Django apps, best‑practice patterns, and practical code snippets that help you turn a simple idea into a production‑ready multi‑vendor store.

Why Choose Django for a Multi‑Vendor Marketplace?

  • Rapid development: Django’s admin, authentication system, and built‑in security features reduce boilerplate code.
  • Scalable ORM: Handles complex relationships between vendors, products, orders, and commissions with ease.
  • Extensible ecosystem: Packages like django-oscar, django-shop, and django-mptt accelerate marketplace features.
  • Strong community: Extensive documentation, tutorials, and third‑party plugins keep you from reinventing the wheel.

Core Components of a Django Multi‑Vendor E‑Commerce Platform

1. User Management & Vendor Onboarding

Separate the concepts of Customer and Vendor while sharing the same User model. A common approach is to extend AbstractUser and add a profile_type field.

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    PROFILE_CHOICES = (
        ('customer', 'Customer'),
        ('vendor',   'Vendor'),
    )
    profile_type = models.CharField(
        max_length=10,
        choices=PROFILE_CHOICES,
        default='customer',
    )

After registration, vendors complete an onboarding form that captures store name, tax information, and payment details. Store this data in a dedicated VendorProfile model linked via a OneToOneField.

2. Product Catalog with Hierarchical Categories

Multi‑vendor platforms need flexible category trees. django-mptt (Modified Preorder Tree Traversal) is perfect for this.

from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
    name = models.CharField(max_length=255)
    parent = TreeForeignKey(
        'self',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='children'
    )
    class MPTTMeta:
        order_insertion_by = ['name']

Each Product links to a Vendor and a Category, allowing sellers to manage their own inventory while the marketplace presents a unified catalog.

3. Shopping Cart & Checkout Flow

The cart can be session‑based for anonymous users and persisted for logged‑in shoppers. Store cart items in a model that references both Product and Vendor to calculate per‑vendor subtotals.

class CartItem(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    session_key = models.CharField(max_length=40, null=True, blank=True)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    vendor = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=1)
    added_at = models.DateTimeField(auto_now_add=True)

4. Order Management & Split Payments

When a customer checks out, the system creates a single Order object with related OrderItem entries. Each OrderItem belongs to a specific vendor, enabling split‑payment logic.

class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    total_amount = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)
    status = models.CharField(max_length=20, default='pending')

class OrderItem(models.Model):
    order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.PROTECT)
    vendor = models.ForeignKey(VendorProfile, on_delete=models.PROTECT)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    quantity = models.PositiveIntegerField()

Integrate with payment gateways (Stripe Connect, PayPal Adaptive Payments, or Razorpay) to route funds directly to each vendor after deducting marketplace commission.

5. Vendor Dashboard

A dedicated dashboard gives sellers insight into sales, inventory, and payouts. Use Django’s class‑based views combined with django-tables2 for sortable tables and django-chartjs for visual analytics.

Step‑by‑Step Blueprint to Build the Platform

Step 1 – Set Up the Project Structure

  1. Create a new Django project: django-admin startproject marketplace
  2. Inside the project, generate core apps:
    • accounts – custom user and vendor profiles
    • catalog – categories and products
    • cart – cart logic
    • orders – order processing and payments
    • dashboard – vendor admin area
  3. Install required third‑party packages:
    pip install django django-mptt django-rest-framework django-allauth stripe django-tables2 django-chartjs

Step 2 – Configure Settings for a Multi‑Vendor Environment

# marketplace/settings.py
INSTALLED_APPS = [
    # Django core
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Third‑party
    'rest_framework',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'mptt',
    'django_tables2',
    'chartjs',
    # Local apps
    'accounts',
    'catalog',
    'cart',
    'orders',
    'dashboard',
]

AUTH_USER_MODEL = 'accounts.User'

# Stripe Connect settings (example)
STRIPE_CLIENT_ID = os.getenv('STRIPE_CLIENT_ID')
STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY')
STRIPE_WEBHOOK_SECRET = os.getenv('STRIPE_WEBHOOK_SECRET')

Step 3 – Build the Vendor Onboarding Flow

Leverage django-allauth for authentication, then add a view that captures vendor details and creates a Stripe Connect account.

def vendor_signup(request):
    if request.method == 'POST':
        form = VendorSignupForm(request.POST, request.FILES)
        if form.is_valid():
            user = form.save(commit=False)
            user.profile_type = 'vendor'
            user.save()
            VendorProfile.objects.create(user=user, **form.cleaned_data)
            # Redirect to Stripe onboarding
            return redirect('stripe_onboard')
    else:
        form = VendorSignupForm()
    return render(request, 'accounts/vendor_signup.html', {'form': form})

Step 4 – Implement the Product Listing API

Expose product data via Django REST Framework so mobile apps or third‑party front‑ends can consume it.

class ProductSerializer(serializers.ModelSerializer):
    vendor = serializers.CharField(source='vendor.store_name')
    category = serializers.CharField(source='category.name')

    class Meta:
        model = Product
        fields = ['id', 'name', 'description', 'price', 'vendor', 'category', 'stock']

class ProductListView(generics.ListAPIView):
    queryset = Product.objects.filter(active=True)
    serializer_class = ProductSerializer
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_fields = ['category', 'vendor']
    search_fields = ['name', 'description']
    ordering_fields = ['price', 'created_at']

Step 5 – Handle Split Payments with Stripe Connect

When an order is placed, create a PaymentIntent for each vendor and attach the marketplace’s commission as an application fee.

import stripe

stripe.api_key = settings.STRIPE_SECRET_KEY

def create_vendor_payment_intent(order_item):
    vendor_account_id = order_item.vendor.stripe_account_id
    amount = int(order_item.price * order_item.quantity * 100)  # cents
    application_fee = int(amount * settings.MARKETPLACE_COMMISSION_RATE)

    intent = stripe.PaymentIntent.create(
        amount=amount,
        currency='usd',
        payment_method_types=['card'],
        transfer_data={'destination': vendor_account_id},
        application_fee_amount=application_fee,
    )
    return intent.client_secret

Step 6 – Design the Vendor Dashboard

Use class‑based generic views with django-tables2 to list orders, and chartjs to visualize sales trends.

class VendorOrderTable(tables.Table):
order_id = tables.Column(verbose_name='Order')
total = tables.Column()
status = tables.Column()
created_at = tables.DateColumn()

class Meta:
model = OrderItem
template_name = 'django_tables2/bootstrap.html'
fields = ('order_id', 'total', 'status', 'created_at')

class DashboardView(LoginRequiredMixin, TemplateView):
template_name = 'dashboard/index.html

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *