Build an E-commerce Website with Django and Stripe Payments

by Didin J. on Oct 15, 2025 Build an E-commerce Website with Django and Stripe Payments

Build a complete e-commerce website using Django and Stripe Payments. Learn to create products, carts, and secure checkout with real-time payment confirmation.

In today’s digital economy, building a secure and scalable e-commerce platform has never been easier — especially with Django, one of the most powerful Python web frameworks, and Stripe, a developer-friendly payment gateway trusted by millions worldwide. In this tutorial, you’ll learn how to create a complete e-commerce website using Django 5.2.7 and integrate Stripe Checkout to handle payments safely and efficiently.

We’ll start from scratch by setting up a Django project, designing models for products and orders, implementing a session-based shopping cart, and connecting it to Stripe for payment processing. You’ll also learn how to handle webhooks to confirm payments automatically and update order statuses in real time. By the end of this guide, you’ll have a fully functional online store that you can deploy to production with secure HTTPS and environment-based configuration.

Whether you’re a Python developer looking to expand your skills or an entrepreneur aiming to launch your online business, this step-by-step tutorial will give you the foundation to build, customize, and scale your own e-commerce solution using Django and Stripe.

Prerequisites & versions

  • Python 3.11+ (works with Python 3.11–3.13; confirm your environment).

  • Django 5.2.7. 

  • Stripe Python SDK v13.0.0. 

  • A Stripe account (test keys are enough for local dev).

  • (Optional) PostgreSQL for production.


Section 1: Project Setup and Dependencies Installation

In this section, you’ll set up a new Django project, create a virtual environment, and install the dependencies required for building the e-commerce application with Stripe integration.

1.1 Create a New Project Folder

Start by creating a directory for your project and navigating into it:

mkdir django-stripe-ecommerce
cd django-stripe-ecommerce

1.2 Create a Virtual Environment

Create and activate a virtual environment (recommended for isolating dependencies):

For macOS/Linux:

python3 -m venv venv
source venv/bin/activate

For Windows:

python -m venv venv
venv\Scripts\activate

1.3 Install Required Packages

Now install Django and Stripe SDK:

pip install django==5.0.7 stripe==10.4.0 python-dotenv

Here’s what each package does:

  • Django – the main web framework.

  • Stripe – official Stripe Python SDK for creating checkout sessions and handling webhooks.

  • python-dotenv – used to load environment variables from a .env file.

1.4 Create Django Project and Apps

Generate the Django project:

django-admin startproject django_stripe_ecommerce .

Then, create the main apps for this project:

python manage.py startapp products
python manage.py startapp cart
python manage.py startapp orders

1.5 Configure Installed Apps

Open django_stripe_ecommerce/settings.py and add the new apps:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Local apps
    'products',
    'cart',
    'orders',
]

1.6 Configure Static and Template Paths

Still in settings.py, update the TEMPLATES and STATICFILES_DIRS sections to recognize global directories:

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'cart.context_processors.cart_total',  # custom cart processor
            ],
        },
    },
]

STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']

1.7 Create .env for Secrets

Create a .env file in the project root and add your Stripe API keys (replace with your real keys from the Stripe Dashboard):

STRIPE_PUBLISHABLE_KEY=pk_test_123456789
STRIPE_SECRET_KEY=sk_test_123456789
DEBUG=True

Then, load these in settings.py:

from dotenv import load_dotenv
load_dotenv()

import os

STRIPE_PUBLISHABLE_KEY = os.getenv('STRIPE_PUBLISHABLE_KEY')
STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY')
DEBUG = os.getenv('DEBUG') == 'True'

1.8 Run Initial Migrations and Start Server

Finally, apply migrations and run the development server to confirm everything is working:

python manage.py migrate
python manage.py runserver

You should see the Django welcome page at:

👉 http://127.0.0.1:8000/

Build an E-commerce Website with Django and Stripe Payments - django page

At this point:
Your Django project is ready with basic structure, environment configuration, and apps created. Next, we’ll build the Product Model and Display Pages to show your e-commerce catalog.


Section 2: Creating the Product Model and Display Page

In this section, we’ll define a Product model, register it in the admin panel, and create a simple product listing page to display all products on the front end.

2.1 Define the Product Model

Open the file products/models.py and add the following code:

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    image = models.ImageField(upload_to='products/', blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

    @property
    def formatted_price(self):
        return f"${self.price:.2f}"

📝 Explanation:

  • name, description, price, and image represent essential product information.

  • formatted_price is a helper property to display prices nicely in templates.

2.2 Register Product in Admin

Open products/admin.py and register the model so you can manage products easily from Django Admin:

from django.contrib import admin
from .models import Product

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ('name', 'price', 'created_at')
    search_fields = ('name',)

Now run the following commands to apply the database migration and create an admin user:

python -m pip install Pillow
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser

Follow the prompts to set up your superuser credentials.

Then start the server and log in to the admin site:

👉 http://127.0.0.1:8000/admin/

You can now add new products using the admin interface.

2.3 Create Product Views and URLs

Open products/views.py and create a simple view to display all products:

from django.shortcuts import render
from .models import Product

def product_list(request):
    products = Product.objects.all().order_by('-created_at')
    return render(request, 'products/product_list.html', {'products': products})

Then, create a new file products/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.product_list, name='product_list'),
]

Now, include this in your main project django_stripe_ecommerce/urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('products.urls')),
]

2.4 Create Product List Template

Create a template at:

products/templates/products/product_list.html

Add the following HTML:

{% extends 'base.html' %}
{% load static %}

{% block content %}
<div class="container">
  <h2 class="text-center mt-4">Our Products</h2>
  <div class="product-grid">
    {% for product in products %}
    <div class="product-card">
      <img src="{{ product.image.url }}" alt="{{ product.name }}" />
      <h3>{{ product.name }}</h3>
      <p>{{ product.description|truncatechars:100 }}</p>
      <p class="price">{{ product.formatted_price }}</p>
      <button class="add-to-cart">Add to Cart</button>
    </div>
    {% endfor %}
  </div>
</div>
{% endblock %}

2.5 Add Basic Product Styles

Create the file:

products/static/products/css/products.css

Add simple styles:

.container {
  width: 90%;
  margin: 0 auto;
}

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 20px;
  margin-top: 30px;
}

.product-card {
  background: #fff;
  border: 1px solid #ddd;
  border-radius: 10px;
  padding: 15px;
  text-align: center;
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  transition: transform 0.2s;
}

.product-card:hover {
  transform: scale(1.03);
}

.product-card img {
  max-width: 100%;
  border-radius: 10px;
}

.price {
  font-weight: bold;
  color: #333;
}

.add-to-cart {
  background: #0a74da;
  color: white;
  border: none;
  padding: 10px 15px;
  border-radius: 5px;
  cursor: pointer;
}

.add-to-cart:hover {
  background: #095aba;
}

Then include this stylesheet in your root/templates/base.html (under <head>):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>{% block title %}My Django Shop{% endblock %}</title>
    <meta
      name="description"
      content="{% block meta_desc %}A simple Django e-commerce demo with Stripe Checkout.{% endblock %}"
    />

    <!-- Styles -->
    <link rel="stylesheet" href="{% static 'css/styles.css' %}" />
    <link rel="stylesheet" href="{% static 'products/css/products.css' %}" />

    <!-- Stripe.js (loaded early) -->
    <script src="https://js.stripe.com/v3/"></script>

    {% block head_extra %}{% endblock %}
  </head>
  <body>
    <header class="site-header">
      <div class="container header-inner">
        <a class="brand" href="{% url 'store:product_list' %}">Djamware Shop</a>
        <nav class="nav">
          <a href="{% url 'store:product_list' %}">Products</a>
          <a href="{% url 'store:cart_detail' %}" id="cart-link"
            >Cart (<span id="cart-count"
              >{{ request.session.cart|length|default:0 }}</span
            >)</a
          >
        </nav>
      </div>
    </header>

    <main class="container">
      {% if messages %}
      <ul class="messages">
        {% for message in messages %}
        <li class="msg {{ message.tags }}">{{ message }}</li>
        {% endfor %}
      </ul>
      {% endif %} {% block content %}{% endblock %}
    </main>

    <footer class="site-footer">
      <div class="container">
        &copy; {{ now.year }} Djamware Shop · Built with Django & Stripe
      </div>
    </footer>

    <!-- Shared JS (CSRF helpers, small UI utilities) -->
    <script>
      // Simple helper to read cookie (Django CSRF cookie name 'csrftoken')
      function getCookie(name) {
        const v = document.cookie
          .split("; ")
          .find((row) => row.startsWith(name + "="));
        return v ? decodeURIComponent(v.split("=")[1]) : null;
      }
      const CSRF_TOKEN = getCookie("csrftoken");
    </script>

    <script src="{% static 'js/cart.js' %}"></script>
    <script src="{% static 'js/checkout.js' %}"></script>

    {% block body_extra %}{% endblock %}
  </body>
</html>

✅ At this point:

You now have:

  • A Product model stored in the database.

  • An Admin interface to manage products.

  • A Public product listing page showing images, names, and prices.


Section 3: Building the Shopping Cart Functionality

Now that your products are displayed, let’s make the e-commerce site interactive by allowing users to add products to a shopping cart, view cart details, update quantities, and remove items — all stored in their Django session.

3.1 Create a cart.py Helper File

Inside your cart/ app, create a new file:

cart/cart.py

Add the following class to manage the shopping cart logic:

from decimal import Decimal
from django.conf import settings
from products.models import Product

class Cart:
    def __init__(self, request):
        self.session = request.session
        cart = self.session.get('cart')
        if not cart:
            cart = self.session['cart'] = {}
        self.cart = cart

    def add(self, product_id, quantity=1):
        product = Product.objects.get(id=product_id)
        product_id_str = str(product_id)

        if product_id_str not in self.cart:
            self.cart[product_id_str] = {
                'name': product.name,
                'price': str(product.price),
                'quantity': 0,
                'image': product.image.url if product.image else '',
            }
        self.cart[product_id_str]['quantity'] += quantity
        self.save()

    def remove(self, product_id):
        product_id_str = str(product_id)
        if product_id_str in self.cart:
            del self.cart[product_id_str]
            self.save()

    def clear(self):
        self.session['cart'] = {}
        self.session.modified = True

    def save(self):
        self.session.modified = True

    def __iter__(self):
        for item in self.cart.values():
            item['price'] = Decimal(item['price'])
            item['total_price'] = item['price'] * item['quantity']
            yield item

    def get_total_price(self):
        return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values())

    def __len__(self):
        return sum(item['quantity'] for item in self.cart.values())

📝 Explanation:

  • add() — adds a product or increases quantity.

  • remove() — removes a product from the cart.

  • clear() — empties the cart.

  • __iter__() — allows easy looping in templates.

  • get_total_price() — calculates total cost.

  • The cart is stored in request.session, so it’s persistent per user session.

3.2 Create Cart Views

Open cart/views.py and add the following functions:

from django.shortcuts import render, redirect, get_object_or_404
from products.models import Product
from .cart import Cart

def cart_detail(request):
    cart = Cart(request)
    return render(request, 'cart/cart_detail.html', {'cart': cart})

def cart_add(request, product_id):
    cart = Cart(request)
    cart.add(product_id=product_id)
    return redirect('cart_detail')

def cart_remove(request, product_id):
    cart = Cart(request)
    cart.remove(product_id=product_id)
    return redirect('cart_detail')

def cart_clear(request):
    cart = Cart(request)
    cart.clear()
    return redirect('cart_detail')

3.3 Create Cart URLs

Create a new file cart/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.cart_detail, name='cart_detail'),
    path('add/<int:product_id>/', views.cart_add, name='cart_add'),
    path('remove/<int:product_id>/', views.cart_remove, name='cart_remove'),
    path('clear/', views.cart_clear, name='cart_clear'),
]

Then include these URLs in your main django_stripe_ecommerce/urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('products.urls')),
    path('cart/', include('cart.urls')),
]

3.4 Create Cart Template

Create the file:

cart/templates/cart/cart_detail.html

Add this HTML:

{% extends 'base.html' %}
{% load static %}

{% block content %}
<div class="container mt-5">
  <h2 class="text-center mb-4">Your Shopping Cart</h2>

  {% if cart|length == 0 %}
  <p class="text-center">Your cart is empty.</p>
  {% else %}
  <table class="cart-table">
    <thead>
      <tr>
        <th>Product</th>
        <th>Quantity</th>
        <th>Price</th>
        <th>Total</th>
        <th>Action</th>
      </tr>
    </thead>
    <tbody>
      {% for item in cart %}
      <tr>
        <td>
          <img src="{{ item.image }}" alt="{{ item.name }}" class="cart-img">
          {{ item.name }}
        </td>
        <td>{{ item.quantity }}</td>
        <td>${{ item.price }}</td>
        <td>${{ item.total_price }}</td>
        <td><a href="{% url 'cart_remove' forloop.counter %}" class="remove">Remove</a></td>
      </tr>
      {% endfor %}
    </tbody>
  </table>

  <div class="cart-total">
    <h3>Total: ${{ cart.get_total_price }}</h3>
    <a href="{% url 'cart_clear' %}" class="btn-clear">Clear Cart</a>
    <a href="{% url 'checkout' %}" class="btn-checkout">Proceed to Checkout</a>
  </div>
  {% endif %}
</div>
{% endblock %}

3.5 Add Styles for Cart Page

Create:

cart/static/cart/css/cart.css
.cart-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 20px;
}

.cart-table th,
.cart-table td {
  padding: 12px;
  border: 1px solid #ddd;
  text-align: center;
}

.cart-img {
  width: 50px;
  border-radius: 5px;
  margin-right: 10px;
}

.cart-total {
  margin-top: 30px;
  text-align: right;
}

.btn-checkout,
.btn-clear {
  background: #0a74da;
  color: #fff;
  padding: 10px 15px;
  text-decoration: none;
  border-radius: 5px;
  margin-left: 10px;
}

.btn-clear {
  background: #dc3545;
}

Include this file in base.html or only in the cart page if preferred.

3.6 Update Product Buttons to Add to Cart

In your products/templates/products/product_list.html, update the Add to Cart button like this:

<a href="{% url 'cart_add' product.id %}" class="add-to-cart">Add to Cart</a>

✅ At this point:

You now have a fully functional shopping cart that:

  • Stores cart data in sessions

  • Allows adding/removing/clearing items

  • Displays a running total

  • Shows total item count (via context processor)


Section 4: Implementing Stripe Checkout Integration

In this section, we’ll integrate Stripe Checkout into the Django e-commerce app so customers can pay securely with credit or debit cards.
Stripe Checkout handles all the complex parts — PCI compliance, 3D Secure authentication, and a beautiful, mobile-friendly interface — letting you focus on your app logic.

1. Create a Stripe Account and Get API Keys

  1. Go to https://dashboard.stripe.com.

  2. Create or log into your Stripe account.

  3. Navigate to Developers → API keys.

  4. Copy your Publishable key and Secret key — you’ll need both.

2. Install Stripe SDK

Run the following command in your virtual environment:

pip install stripe

3. Configure Stripe Keys in settings.py

Add the following to the bottom of your settings.py file:

# Stripe configuration
STRIPE_PUBLIC_KEY = 'your-publishable-key-here'
STRIPE_SECRET_KEY = 'your-secret-key-here'
STRIPE_SUCCESS_URL = 'http://127.0.0.1:8000/success/'
STRIPE_CANCEL_URL = 'http://127.0.0.1:8000/cancel/'

💡 In production, you’ll store these keys in environment variables instead of hardcoding them.

4. Create a New App for Checkout

Let’s keep payment logic clean by creating a new app:

python manage.py startapp payments

Then add it to INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
    ...
    'cart',
    'store',
    'payments',
]

5. Define the Checkout View

Edit payments/views.py:

import stripe
from django.conf import settings
from django.shortcuts import redirect, render
from django.views import View

stripe.api_key = settings.STRIPE_SECRET_KEY


class CreateCheckoutSessionView(View):
    def post(self, request, *args, **kwargs):
        cart = request.session.get('cart', {})
        line_items = []

        for product_id, item in cart.items():
            line_items.append({
                'price_data': {
                    'currency': 'usd',
                    'product_data': {'name': item['name']},
                    'unit_amount': int(item['price'] * 100),
                },
                'quantity': item['quantity'],
            })

        session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=line_items,
            mode='payment',
            success_url=settings.STRIPE_SUCCESS_URL,
            cancel_url=settings.STRIPE_CANCEL_URL,
        )

        return redirect(session.url, code=303)

6. Add Success and Cancel Views

Still in payments/views.py, add:

def success_view(request):
    request.session['cart'] = {}  # clear the cart after payment
    return render(request, 'payments/success.html')


def cancel_view(request):
    return render(request, 'payments/cancel.html')

7. Add Payment URLs

Create a new file payments/urls.py:

from django.urls import path
from .views import CreateCheckoutSessionView, success_view, cancel_view

urlpatterns = [
    path('create-checkout-session/', CreateCheckoutSessionView.as_view(), name='create_checkout_session'),
    path('success/', success_view, name='success'),
    path('cancel/', cancel_view, name='cancel'),
]

Include it in the main urls.py (e.g., in django_stripe_ecommerce/urls.py):

path('', include('store.urls')),
path('cart/', include('cart.urls')),
path('payments/', include('payments.urls')),

8. Create Payment Templates

In templates/payments/success.html:

{% extends "base.html" %}
{% block content %}
<div class="text-center mt-5">
  <h2>Payment Successful!</h2>
  <p>Thank you for your purchase. Your order is being processed.</p>
  <a href="/" class="btn btn-primary mt-3">Back to Store</a>
</div>
{% endblock %}

In templates/payments/cancel.html:

{% extends "base.html" %}
{% block content %}
<div class="text-center mt-5">
  <h2>Payment Cancelled</h2>
  <p>Your payment was cancelled. You can try again anytime.</p>
  <a href="/cart/" class="btn btn-warning mt-3">Return to Cart</a>
</div>
{% endblock %}

9. Add Checkout Button to the Cart Page

Edit your templates/cart/cart_detail.html (or wherever your cart view is):

<form action="{% url 'create_checkout_session' %}" method="POST">
  {% csrf_token %}
  <button type="submit" class="btn btn-success mt-3">Checkout with Stripe</button>
</form>

10. Test the Checkout Flow

Run your server:

python manage.py runserver
  • Add items to your cart.

  • Click Checkout with Stripe.

  • You should be redirected to Stripe’s payment page.

  • Use Stripe’s test card numbers (e.g., 4242 4242 4242 4242, any future expiry, any CVC).

  • After successful payment, you’ll be redirected to /success/.

You’ve successfully integrated Stripe Checkout into your Django e-commerce app!


Section 5: Handling Stripe Webhooks and Order Confirmation

1. What Are Webhooks?

A webhook is a message Stripe sends to your server to notify you about important events — such as:

  • checkout.session.completed → payment succeeded

  • payment_intent.payment_failed → payment failed

  • charge.refunded → refund processed

We’ll handle checkout.session.completed to mark an order as paid.

2. Create a Webhook Endpoint in Django

Open payments/views.py and add the following imports and view:

import json
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator

@csrf_exempt
def stripe_webhook(request):
    payload = request.body
    sig_header = request.META.get('HTTP_STRIPE_SIGNATURE')
    endpoint_secret = 'your-webhook-signing-secret'  # Replace with your actual secret
    event = None

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, endpoint_secret
        )
    except ValueError:
        # Invalid payload
        return HttpResponse(status=400)
    except stripe.error.SignatureVerificationError:
        # Invalid signature
        return HttpResponse(status=400)

    # Handle the event
    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        handle_successful_payment(session)

    return HttpResponse(status=200)

3. Add a Payment Handler Function

Still in payments/views.py, define handle_successful_payment(session):

from store.models import Product
from django.core.mail import send_mail
from django.conf import settings

def handle_successful_payment(session):
    # You could retrieve metadata if you attach it to checkout sessions
    print(f"Payment was successful for session: {session['id']}")

    # Example: send a confirmation email (optional)
    send_mail(
        subject="Order Confirmation",
        message="Your payment was successful. Thank you for your order!",
        from_email=settings.DEFAULT_FROM_EMAIL,
        recipient_list=["[email protected]"],  # Replace with dynamic user email
        fail_silently=True,
    )

💡 You can extend this function later to:

  • Create an Order record in your database

  • Save line items

  • Update stock levels

  • Send a receipt or invoice

4. Add the Webhook URL

In payments/urls.py, register the new route:

from .views import stripe_webhook

urlpatterns = [
    path('create-checkout-session/', CreateCheckoutSessionView.as_view(), name='create_checkout_session'),
    path('success/', success_view, name='success'),
    path('cancel/', cancel_view, name='cancel'),
    path('webhook/', stripe_webhook, name='stripe_webhook'),
]

5. Get Your Webhook Signing Secret

 

  1. In your terminal, run:

     
    stripe listen --forward-to localhost:8000/payments/webhook/

     

  2. This command will output something like:

     
    Ready! Your webhook signing secret is whsec_12345abcde

     

  3. Now Stripe will forward events from your account to your local Django app.

  4. Copy that secret and replace it in your code:

     
    endpoint_secret = 'whsec_12345abcde'

     

Now Stripe will forward events from your account to your local Django app.

6. Test Webhook Events

You can manually trigger a webhook event from Stripe CLI:

stripe trigger checkout.session.completed

Your Django console should log something like:

Payment was successful for session: cs_test_...

If you added email sending, check your console or configure the email backend.

7. (Optional) Create an Order Model

To make things more realistic, you can define an Order model in a new file products/models.py (below your Product model):

class Order(models.Model):
    session_id = models.CharField(max_length=255)
    amount_total = models.DecimalField(max_digits=10, decimal_places=2)
    email = models.EmailField()
    created_at = models.DateTimeField(auto_now_add=True)
    paid = models.BooleanField(default=False)

    def __str__(self):
        return f"Order {self.id} - {self.email}"

Then in handle_successful_payment(session):

from store.models import Order

def handle_successful_payment(session):
    Order.objects.create(
        session_id=session['id'],
        amount_total=session['amount_total'] / 100,
        email=session['customer_details']['email'],
        paid=True
    )
    print(f"✅ Order created for {session['customer_details']['email']}")

8. Verify Payment Flow

  1. Start the Django server:

     
    python manage.py runserver

     

  2. Start Stripe listener:

     
    stripe listen --forward-to localhost:8000/payments/webhook/

     

  3. Check out again using Stripe test cards.

  4. Watch your Django console — it should log a successful payment and create an Order record.

Congratulations!

You’ve now built a complete Django e-commerce payment flow:

  • Products and cart

  • Stripe Checkout integration

  • Webhook-based payment confirmation

  • Optional order storage and email notifications


Section 6: Final Touches and Deployment

(Environment Variables, HTTPS, and Static Files)

Now that your Django + Stripe e-commerce app works locally, it’s time to prepare it for real-world deployment with best practices for security and performance.

1. Move Sensitive Data to Environment Variables

You should never hardcode your secret keys (like STRIPE_SECRET_KEY, DJANGO_SECRET_KEY, etc.) in settings.py.

Step 1: Install python-dotenv

pip install python-dotenv

Step 2: Create a .env file at the root of your project

SECRET_KEY=django-insecure-your-secret-key
DEBUG=False
STRIPE_PUBLIC_KEY=pk_live_xxxxxxxxxxxxx
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx
ALLOWED_HOSTS=yourdomain.com

💡 Never commit .env files to Git. Add it to .gitignore.

Step 3: Load .env in settings.py

At the top of settings.py, import os and load environment variables:

import os
from dotenv import load_dotenv
load_dotenv()

SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = os.getenv('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',')
STRIPE_PUBLIC_KEY = os.getenv('STRIPE_PUBLIC_KEY')
STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY')

2. Configure Static Files for Production

When deploying, Django doesn’t automatically serve static files (CSS, JS, images) — you need to collect them into one directory.

Step 1: Update settings.py

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

Step 2: Run collectstatic

python manage.py collectstatic

This gathers all CSS, JS, and images from your apps into staticfiles/, which your web server (like Nginx or Gunicorn) can serve.

3. Enforce HTTPS and Secure Settings

To protect user data — especially during checkout — HTTPS is mandatory.

In settings.py, add the following for production:

SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

If you’re deploying behind a reverse proxy (like Render or Heroku), also add:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

4. Configure Email Settings (Optional but Recommended)

For order confirmations and notifications, configure Django’s email backend:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.getenv('EMAIL_USER')
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_PASS')
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

Then add these to .env:

[email protected]
EMAIL_PASS=your_app_password

5. Choose a Deployment Platform

You can deploy your Django project to several platforms easily. Here are 3 common options:

Render (recommended for beginners)

  1. Push your project to GitHub.

  2. Go to https://render.com → “New Web Service”.

  3. Connect your repo, set the environment variables from .env.

  4. Use:

    Build Command: pip install -r requirements.txt && python manage.py collectstatic --noinput
    Start Command: gunicorn django_stripe_ecommerce.wsgi
  5. Render automatically provides HTTPS and a free PostgreSQL instance if needed.

Railway

Similar to Render, but faster to set up with one-click deploy from GitHub.

Vercel / Fly.io / AWS

For advanced users needing more control or multi-service setups.

6. Test the Live Stripe Integration

Before going live:

  1. Set Stripe API keys to Live mode in your dashboard.

  2. Update your .env with the live keys.

  3. Update your webhook endpoint in Stripe to point to your deployed URL:

     
    https://yourdomain.com/payments/webhook/

     

  4. Test again with a real card (or use test mode for dry runs).

7. Final Project Checklist ✅

Task Status
Django project structured with apps (store, cart, payments)
Stripe Checkout is integrated and functional
Webhooks verified
Environment variables configured
Static files collected
HTTPS enforced
Deployed with environment-specific settings


Conclusion + Next Steps

Congratulations! 🎉 You’ve just built a fully functional e-commerce website using Django and Stripe Payments — from product listings to checkout and webhook-based payment confirmation. This project demonstrates how Django’s robust backend framework and Stripe’s modern payment APIs work together to create a secure, scalable online store.

Here’s what you accomplished in this tutorial:

  • Set up a modular Django project with separate apps for products, carts, and payments

  • Created a Product model and a dynamic product page

  • Built a session-based shopping cart to store and manage items

  • Integrated Stripe Checkout for real-time, secure card payments

  • Implemented Stripe webhooks to confirm completed orders

  • Prepared your project for production deployment with environment variables, HTTPS, and static file management

This architecture gives you a solid foundation to build a complete e-commerce platform — and Django’s flexibility makes it easy to extend further.

🚀 Next Steps & Enhancements

Now that your store is working, you can make it even better by adding:

  1. User Authentication & Profiles
    Let users register, log in, and view their order history. Use Django’s built-in User model or extend it for more features.

  2. Order History & Admin Dashboard
    Create admin views or customer dashboards to display past purchases, invoices, and order details.

  3. Product Categories & Search
    Add filtering by category or implement full-text search with PostgreSQL or Django Haystack.

  4. Discount Codes & Coupons
    Offer promotional discounts using coupon models tied to order totals.

  5. Inventory Management
    Track stock levels, automatically reduce inventory after successful payments, and display “Out of Stock” notices.

  6. Email Receipts & Notifications
    Use Django’s email backend or a service like SendGrid to send branded order confirmation emails.

  7. Cloud Deployment
    Deploy to production using Render, Railway, or AWS for real-world scalability.

💬 Final Thoughts

This tutorial covered everything you need to get started with Django and Stripe integration — and it’s just the beginning. The skills you’ve learned here apply to countless real-world scenarios, from SaaS billing to subscription systems and digital product stores.

Keep experimenting, refining, and building — your next project could be the next great e-commerce platform!

You can find the full source code on our GitHub.

That's just the basics. If you need more deep learning about Python, Django, FastAPI, Flask, and related, you can take the following cheap course:

Thanks!