Every Python e-commerce article I've read follows the same structure: list the frameworks, list the features, add a conclusion that says "Python is great for e-commerce." Technically accurate. Not very useful if you're actually building something.
This is a more practical take. I want to cover the decisions that actually matter — framework selection with real reasoning, the features that are harder than they look, code patterns worth knowing, and the architectural traps that are much easier to avoid early than fix later.
Start Here: Should You Actually Build Custom?
Before any framework discussion — if your e-commerce requirements are standard (product catalog, cart, checkout, Stripe payments, order management), consider whether you need to build at all. Shopify, WooCommerce, or even Saleor's hosted offering might get you to market faster with less ongoing maintenance burden.
Custom Python makes sense when:
- Your product model is unusual (configurables, bundles, subscriptions, digital goods with complex delivery)
- You're building a multi-vendor marketplace
- You need deep integration with existing backend services
- You want to add ML-powered features (recommendations, dynamic pricing, demand forecasting) and want them to live in the same codebase
If you can't articulate why Shopify doesn't work for you, you might be solving the wrong problem.
Framework Comparison: The Honest Version
Django
Django is the right default. Not because it's the best in every dimension, but because it solves the right problems out of the box for commerce:
- ORM with migrations → your product and order models are versioned from day one
- Admin interface → operations teams can manage inventory, orders, and customers without touching code
- Built-in auth → user registration, login, sessions, permissions
- Form handling and CSRF protection → security fundamentals handled
# Django model for a basic product — you get admin, ORM queries, migrations for free
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField(default=0)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
def is_in_stock(self):
return self.stock > 0
Enter fullscreen mode Exit fullscreen mode
This model is immediately queryable, immediately visible in admin, and immediately migratable. That's Django's value proposition.
Flask
Flask is a deliberate minimalism choice, not a default. You get routing and request handling. Everything else — ORM, auth, form validation, caching, admin — is a library you add yourself.
# Flask requires you to wire everything manually
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
app = Flask(__name__)
db = SQLAlchemy(app)
login_manager = LoginManager(app)
# You're assembling pieces; Django ships them assembled
Enter fullscreen mode Exit fullscreen mode
Flask makes sense when you're building a thin API layer over existing services, or when your "e-commerce platform" is really a specialized checkout flow sitting on top of proprietary backend logic. In those cases, you don't want Django's opinions — you want to compose your own.
Saleor
Saleor is a Django-based, GraphQL-first e-commerce framework. It's genuinely production-ready and ships with payment processing, multi-currency support, a product catalog, and a React-based dashboard.
The trade-off: you're inheriting Saleor's data model. When your requirements fit, it's a significant head start. When they don't, you're working against the framework rather than with it.
Worth evaluating if your requirements are within the standard commerce domain and you want to move fast.
Oscar
Oscar is another Django e-commerce framework, more flexible than Saleor in terms of data model customization. It's designed to be forked and extended — the "fork to customize" model rather than "override to customize."
# Oscar setup
pip install django-oscar
# Fork the app you want to customize
python manage.py oscar_fork_app catalogue myshop/
Enter fullscreen mode Exit fullscreen mode
Oscar's product abstraction (product classes, attributes, variants) handles a wide range of product structures without requiring schema changes. Good for complex catalogs.
The Eight Core Features — What's Actually Hard
1. Product Management
Straightforward for simple catalogs. Gets complicated fast when you have:
- Product variants (size × color combinations)
- Configurable products (custom engraving, bundle options)
- Digital products with delivery mechanisms
- Products with different tax rules or shipping profiles
Oscar's product model handles variants well out of the box. If you're on raw Django, design your product schema carefully before you have real data — migrating product models with inventory is painful.
2. Authentication and Security
Django's auth system is solid. For commerce specifically, layer on:
# settings.py — minimum security baseline for an e-commerce platform
AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {'min_length': 10}},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
]
SESSION_COOKIE_SECURE = True # HTTPS only
CSRF_COOKIE_SECURE = True
SECURE_HSSL_REDIRECT = True
X_FRAME_OPTIONS = 'DENY'
Enter fullscreen mode Exit fullscreen mode
Two-factor auth for admin access (django-two-factor-auth), rate limiting on login endpoints, and proper PII handling for GDPR/CCPA compliance are all necessary additions.
3. Shopping Cart and Checkout
More complex than it looks. Cart state questions you'll face:
- How do guest carts merge with authenticated user carts on login?
- How do you handle inventory reservation during checkout (soft reserve vs hard reserve)?
- What happens to a cart when a product goes out of stock mid-session?
If your checkout is reasonably standard, start with Saleor's or Oscar's checkout pipeline. These edge cases have already been thought through.
4. Payment Integration
Stripe is the right default for new builds. The Python SDK is well-maintained:
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
def create_payment_intent(amount_cents, currency, metadata):
return stripe.PaymentIntent.create(
amount=amount_cents,
currency=currency,
metadata=metadata,
automatic_payment_methods={"enabled": True},
)
Enter fullscreen mode Exit fullscreen mode
The thing to get right isn't which gateway — it's your payment state model. Payment flows have more edge cases than they appear (failed charges, partial refunds, disputes, webhooks arriving out of order). Model payment state explicitly rather than inferring it from webhook history.
5. Order Management
The operational backbone. Beyond the basic status lifecycle, you need returns and refunds, order editing, and fulfillment integration. Django's ORM makes the data modeling clean:
class Order(models.Model):
class Status(models.TextChoices):
PENDING = 'pending', 'Pending'
CONFIRMED = 'confirmed', 'Confirmed'
PROCESSING = 'processing', 'Processing'
SHIPPED = 'shipped', 'Shipped'
DELIVERED = 'delivered', 'Delivered'
CANCELLED = 'cancelled', 'Cancelled'
REFUNDED = 'refunded', 'Refunded'
user = models.ForeignKey(User, on_delete=models.PROTECT)
status = models.CharField(max_length=20, choices=Status.choices, default=Status.PENDING)
total = models.DecimalField(max_digits=10, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Enter fullscreen mode Exit fullscreen mode
6. Search and Filtering
Django ORM handles simple filtering. For anything beyond that, integrate a real search engine early:
# Elasticsearch via elasticsearch-dsl-py
from elasticsearch_dsl import Document, Text, Keyword, Float
class ProductIndex(Document):
name = Text(analyzer='english')
category = Keyword()
price = Float()
class Index:
name = 'products'
Enter fullscreen mode Exit fullscreen mode
Typesense is a lighter alternative with good Python support and significantly easier self-hosting. Don't add this as an afterthought — retrofitting search infrastructure into an existing data pipeline is harder than building it in from the start.
7. Async Tasks — Set This Up Before You Need It
This one isn't in most feature lists but it should be. Email sends, webhook processing, inventory updates, search index updates, report generation — none of these should run synchronously in a request cycle:
# Celery task for order confirmation email
from celery import shared_task
from django.core.mail import send_mail
@shared_task
def send_order_confirmation(order_id):
order = Order.objects.get(id=order_id)
send_mail(
subject=f'Order #{order.id} confirmed',
message=render_confirmation_email(order),
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[order.user.email],
)
Enter fullscreen mode Exit fullscreen mode
Celery + Redis is the standard setup. Get it in early, because adding it after the fact means touching every place in your codebase that currently runs slow operations synchronously.
8. SEO
Django is genuinely good here — clean URL routing, easy meta tag control, built-in sitemap generation. django-meta handles most of the boilerplate:
# SEO-friendly URL structure
urlpatterns = [
path('shop/<slug:category_slug>/<slug:product_slug>/', views.product_detail, name='product-detail'),
]
# Produces: /shop/mens-shoes/nike-air-max-90/ — clean, descriptive, indexable
Enter fullscreen mode Exit fullscreen mode
For product variants, handle canonical URLs carefully to avoid duplicate content penalties.
The Architectural Decisions to Make Early
Choose your frontend architecture before writing backend code. Django templates (server-rendered) vs. Django REST Framework + React frontend changes how you structure URLs, how you handle authentication (session-based vs JWT), and how you deliver pages to mobile. Either works — but mixing approaches mid-project is expensive.
Model your product schema for where you're going, not where you are. If there's any chance you'll have variants, bundles, or multiple product types, build that flexibility in. Oscar's product abstraction is worth studying even if you don't use Oscar.
Async tasks from day one. Celery + Redis. Don't postpone this.
Set up search infrastructure early. Elasticsearch or Typesense. Don't bolt it on later.
Quick Reference: Framework Selection
| Situation | Recommendation |
|---|---|
| Standard commerce, need to move fast | Saleor |
| Complex catalog, need flexibility | Oscar |
| Standard commerce, greenfield, full control | Django |
| Thin API layer over existing services | Flask |
| Non-standard requirements everywhere | Django from scratch |
At Innostax, we've shipped Python e-commerce platforms at various scales. If you're working through framework selection or architecture for a commerce build, reach out here — happy to think it through.
Originally published on the Innostax Engineering Blog.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.