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, anddjango-mpttaccelerate 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
- Create a new Django project:
django-admin startproject marketplace - Inside the project, generate core apps:
accounts– custom user and vendor profilescatalog– categories and productscart– cart logicorders– order processing and paymentsdashboard– vendor admin area
- 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
Leave a Reply