Python Django Multi-Vendor E-Commerce Platform

Written by

in

Building a thriving online marketplace where dozens—or even hundreds—of independent sellers can showcase their products is no longer a distant dream. With the power of Python Django, developers can create a robust, scalable, and secure multi‑vendor e‑commerce platform that rivals commercial solutions while keeping total ownership and customization in-house. In this guide we’ll explore the core concepts, essential features, and step‑by‑step architecture needed to launch a Django‑based marketplace that delights both vendors and shoppers.

Why Choose Django for a Multi‑Vendor Marketplace?

Django is a high‑level web framework that follows the “batteries‑included” philosophy. Its built‑in admin interface, ORM, authentication system, and security features make it an ideal foundation for complex e‑commerce projects. Below are the key reasons why Django shines for multi‑vendor platforms:

  • Rapid Development: Django’s conventions and reusable apps accelerate the build process.
  • Scalable Architecture: Horizontal scaling with Django’s support for multiple databases, caching, and async views.
  • Security First: Protection against XSS, CSRF, SQL injection, and clickjacking out of the box.
  • Extensible Admin: Vendors can manage inventory, orders, and payouts through a customized admin panel.
  • Strong Community: A vibrant ecosystem of third‑party packages (e.g., django‑rest‑framework, django‑allauth, django‑shop) speeds up feature implementation.

Core Components of a Django Multi‑Vendor Platform

1. Vendor Management

Each seller needs a dedicated profile, store settings, and a dashboard. This is typically handled by extending Django’s User model with a Vendor profile:

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

class User(AbstractUser):
    is_vendor = models.BooleanField(default=False)

class Vendor(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    store_name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)
    logo = models.ImageField(upload_to='vendor_logos/')
    description = models.TextField(blank=True)
    # Additional fields: address, tax_id, payout_method, etc.

2. Product Catalog

Products belong to vendors but share a common catalog schema. Using Django’s GenericForeignKey is unnecessary; a simple foreign key to Vendor keeps queries fast.

class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)

class Product(models.Model):
    vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, related_name='products')
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.PositiveIntegerField()
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

3. Shopping Cart & Checkout

A cart can contain items from multiple vendors. The checkout process must split the order per vendor to handle separate payments, shipping, and commissions.

class Cart(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

class CartItem(models.Model):
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name='items')
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()
    # Cached price to avoid price changes during checkout
    price_at_add = models.DecimalField(max_digits=10, decimal_places=2)

4. Order Splitting & Vendor Payouts

When a buyer places an order, the system creates a parent Order and child VendorOrder records for each vendor involved.

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

class VendorOrder(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='vendor_orders')
    vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
    subtotal = models.DecimalField(max_digits=12, decimal_places=2)
    commission_rate = models.DecimalField(max_digits=4, decimal_places=2, default=0.10)  # 10%
    commission_amount = models.DecimalField(max_digits=12, decimal_places=2)
    payout_status = models.CharField(max_length=20, default='pending')

Essential Third‑Party Packages

  • django‑rest‑framework – Build a clean JSON API for mobile apps or headless front‑ends.
  • django‑allauth – Handles social login, email verification, and password reset.
  • django‑ckeditor or django‑tinymce – Rich‑text editors for product descriptions.
  • django‑storages – Seamless integration with AWS S3 or Google Cloud for media files.
  • django‑celery‑beat – Schedule recurring tasks like daily commission payouts.
  • django‑paygate (or any gateway library) – Connect to Stripe, PayPal, or local payment providers.

Step‑by‑Step Blueprint to Launch the Marketplace

1. Project Setup

# Create a virtual environment
python -m venv venv
source venv/bin/activate

# Install Django and core packages
pip install django djangorestframework django-allauth pillow psycopg2-binary

# Start a new project
django-admin startproject marketplace
cd marketplace

# Create core apps
python manage.py startapp accounts
python manage.py startapp catalog
python manage.py startapp orders
python manage.py startapp payments

2. Configure Settings

In settings.py enable the installed apps, configure the custom user model, and set up media storage.

INSTALLED_APPS = [
    # Default Django apps…
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.sessions',
    # Third‑party
    'rest_framework',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    # Local apps
    'accounts',
    'catalog',
    'orders',
    'payments',
]

AUTH_USER_MODEL = 'accounts.User'

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

# Simple JWT for API authentication (optional)
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

3. Build the Vendor Dashboard

Leverage Django’s admin and create a custom view set for vendors. Example: a simple class‑based view that lists a vendor’s products.

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import ListView
from .models import Product

class VendorProductListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
    model = Product
    template_name = 'vendor/product_list.html'
    paginate_by = 20

    def get_queryset(self):
        return Product.objects.filter(vendor=self.request.user.vendor)

    def test_func(self):
        return self.request.user.is_vendor

4. Implement Search & Filtering

Use django‑filter and Haystack (or Elasticsearch) to let shoppers find products across all vendors.

# Example filterset
import django_filters
from .models import Product

class ProductFilter(django_filters.FilterSet):
    min_price = django_filters.NumberFilter(field_name='price', lookup_expr='gte')
    max_price = django_filters.NumberFilter(field_name='price', lookup_expr='lte')
    category = django_filters.ModelChoiceFilter(queryset=Category.objects.all())

    class Meta:
        model = Product
        fields = ['category', 'min_price', 'max_price']

5. Handle Payments and Commissions

Integrate Stripe Connect (or PayPal Adaptive Payments) to collect payments from buyers and automatically split funds between the marketplace and each vendor.

# Pseudo‑code for a Stripe Connect charge
import stripe

stripe.api_key = settings.STRIPE_SECRET_KEY

def create_payment_intent(order):
    # Calculate total amount in cents
    amount = int(order.total_amount * 100)

    # Create a payment intent linked to the marketplace account
    intent = stripe.PaymentIntent.create(
        amount=amount,
        currency='usd',
        payment_method_types=['card'],
        metadata={'order_id': order.id}
    )
    return intent.client_secret

6. Automate Vendor Payouts

Schedule a nightly Celery task that iterates over VendorOrder records with payout_status='pending', transfers the net amount to the vendor’s Stripe account, and marks the payout as completed.

@shared_task
def process_vendor_payouts():
    pending = VendorOrder.objects.filter(payout_status='pending')
    for vo in pending:
        net_amount = vo.subtotal - vo.commission_amount
        stripe.Transfer.create(
            amount=int(net_amount * 100),
            currency='usd',
            destination=vo.vendor.stripe_account_id,
            description=f'Payout for Order {vo.order.id}'
        )
        vo.payout_status = 'paid'
        vo.save()

Best Practices for Performance and SEO

  • Cache heavy queries:

Comments

Leave a Reply

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