Integrating Stripe Payments in Django: Step-by-Step Guide for Developers

Are you looking to implement Stripe Integration with Django? This guide will walk you through the process step by step, from setting up Stripe to creating a seamless payment flow.

In today’s digital world, online payments have become an integral part of eCommerce websites and web applications. One of the most popular payment gateways is Stripe, known for its ease of use, powerful features, and developer-friendly APIs. If you’re building a Django project and want to integrate Stripe to handle payments, this step-by-step guide will show you how to do it efficiently.

Why Stripe?

Before diving into the integration, let’s briefly explore why Stripe is a great choice for handling payments:

  • Easy Setup: Stripe provides simple, clear documentation and libraries for several programming languages, including Python.
  • Security: It takes care of PCI compliance, which is essential for safely handling credit card information.
  • Global Reach: Stripe supports a wide variety of payment methods and currencies, making it a versatile solution for global transactions.
  • Developer-Friendly: Stripe’s API and tools are designed to simplify common payment use cases, from subscription billing to one-time payments.

Now, let’s walk through integrating Stripe with a Django project.

Project Setup

We’ll create a simple Django project to manage products and orders and integrate Stripe for processing payments. Our basic application will allow customers to view a product, click on “Buy Now,” and then make a payment using Stripe.

You can clone the entire project my Github account

1. Create Virtual Environment

I love to create virtual environments for each project and install the required libraries only for that project. You can follow the instructions below to create the virtual environment for Windows, Linux and MacOS

Windows:
				
					python -m venv venv # create the virtual environemt.

venv\Scripts\activate # activate the environment.
				
			
Linux/Mac:
				
					python3 -m venv venv # create the virtual environment.

source venv/bin/activate # activate the environment.
				
			

2. Install Requirements

Now you have activated the virtual environment, let’s make sure you have python and Django installed. You’ll also need to install the Stripe python library to interact with Stripe’s API.

				
					pip install stripe
pip install django==4.2 # it is the latest stable version as of now.
				
			

3. Setup your Project

Since we’ve now installed the requirements, let’s create our django project, you can run the following command to start the project.

				
					django-admin startproject core . # creates a django project in this folder.
				
			

Now, let’s create the app to use for managing the payment flow in (product listing, product detail page, success and cancel pages), I want to name it app , you can run this command to create it.

				
					python manage.py startapp app
				
			

4. Set Up Stripe API Keys

To use Stripe, you need to sign up for a Stripe account and get your API keys. These keys will allow your Django application to interact with Stripe.

  • Go to Stripe and create an account.
  • Once logged in, go to the Dashboard and find your API keys under Developers > API keys.
  • Copy your Publishable Key and Secret Key.

Add the keys to your Django settings file (core/settings.py):

				
					# settings.py
STRIPE_PUBLISHABLE_KEY = 'pk_test_....'
STRIPE_SECRET_API_KEY = 'sk_test_.....'
				
			

Make sure to never share your secret key publicly. You can use Django’s python-decouple or environment variables to manage this securely.

5. Crafting the models for Products and Orders

I am only focusing on the basics fields of the product and orders models for now. Here is the code:

				
					# app/models.py

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=255)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    image = models.CharField(max_length=255, blank=True, null=True, help_text="The base64 encoded image data")
    
    class Meta:
        verbose_name = 'Product'
        verbose_name_plural = 'Products'
    
    @property
    def image_url(self):
        if not self.image:
            return None
        return f"data:image/png;base64,{self.image}"

    def __str__(self):
        return self.name

class Order(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()
    total_price = models.DecimalField(max_digits=10, decimal_places=2)
    paid = models.BooleanField(default=False)
    paid_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Order'
        verbose_name_plural = 'Orders'

    def __str__(self):
        return f"Order #{self.id} - {self.product.name}"
    
    def calculate_total_price(self):
        return self.product.price * self.quantity

    def save(self, *args, **kwargs):
        self.total_price = self.calculate_total_price()
        super().save(*args, **kwargs)
				
			

6. Run the migrations

Now, you need to run the makemigrations command to create the migrations for the models: 

python manage.py makemigrations

Run the migrate command to add the table (models) to the DB

python manage.py migrate

Now, you can add the models to the admin panel if you need:

				
					from django.contrib import admin
from .models import Product, Order

admin.site.register(Product)
admin.site.register(Order)
				
			

Next, create some test products using the admin panel to see the list them in the product list template.

7. Display the products

app/views.py

Add the views to list the products and show details of a specific product.

				
					from django.shortcuts import render, get_object_or_404

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

def product_detail(request, product_id):
    product = Product.objects.get(pk=product_id)
    return render(request, 'product_detail.html', {'product': product})
				
			

app/urls.py

				
					from django.urls import path

from . import views

urlpatterns = [
    path('', views.product_list, name='product_list'),
    path('<int:product_id>/detail', views.product_detail, name='product_detail'),
]
				
			

Now, let’s create the templates (pages) for these views (controllers). You need to create templates folder inside the app folder, then you need to create base.html file inside the templates folder, we need this page to have the code that’ll be reused by the product list, details page and other pages.

				
					<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}{% endblock %} - My Store</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="{% url 'product_list' %}">My Store</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'product_list' %}">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">About</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">Contact</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container my-4">
        {% block content %}
        {% endblock %}
    </div>
    <footer class="bg-dark text-white py-3">
        <div class="container text-center">
            <p class="mb-0">&copy; 2025 My Store. All rights reserved.</p>
        </div>
    </footer>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
				
			

Now, let’s create the product list and details page, these pages need to be created inside the templates folder, create them as: product_list.html and product_detail.html .

product_list.html 

				
					{% extends "base.html" %}

{% block title %}Product List{% endblock %}

{% block content %}

<style>
    .card:hover {
        box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
        transform: scale(1.05);
        transition: all .2s ease-in-out;
    }
</style>

<h1 class="text-center">Our Products</h1>
<div class="row row-cols-1 row-cols-md-3 g-4 mt-4">
    {% for product in products %}
    <div class="col">
        <div class="card h-100">
            {% if product.image %}
            <img decoding="async" src="{{ product.image_url }}" class="card-img-top" alt="{{ product.name }}">
            {% else %}
            <img decoding="async" src="https://via.placeholder.com/150" class="card-img-top" alt="Placeholder image">
            {% endif %}
            <div class="card-body">
                <h5 class="card-title">{{ product.name }}</h5>
                <p class="card-text">{{ product.description }}</p>
                <p class="card-text"><strong>${{ product.price }}</strong></p>
                <a href="{% url 'product_detail' product.id %}" class="btn btn-primary">View Details</a>
            </div>
        </div>
        
    </div>
    {% endfor %}
</div>
{% endblock %}
				
			

product_detail.html

				
					{% extends "base.html" %}

{% block title %}{{ product.name }} Details{% endblock %}

{% block content %}
<div class="container">
    <div class="row">
        <div class="col-md-6">
            {% if product.image %}
            <img decoding="async" src="{{ product.image_url }}" class="img-fluid rounded" alt="{{ product.name }}">
            {% else %}
            <img decoding="async" src="https://via.placeholder.com/400" class="img-fluid rounded" alt="Placeholder image">
            {% endif %}
        </div>
        <div class="col-md-6">
            <h1>{{ product.name }}</h1>
            <p class="lead">{{ product.description }}</p>
            <p class="h4"><strong>Price:</strong> ${{ product.price }}</p>
            <div class="mt-4">
                <a href="#" class="btn btn-primary">Buy Now</a>
                <a href="{% url 'product_list' %}" class="btn btn-secondary">Back to Products List</a>
            </div>
        </div>
    </div>
</div>
{% endblock %}
				
			

After that we need to include theapp/urls.py to the core/urls.py 

core/urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('app.urls')), # new 
				
			

Now, you can run the project to see the list of the test products you’ve created using the admin panel earlier.

				
					python manage.py runserver
				
			

8. Stripe Payment Integration

Now, we need to add payment logic to our project. The simple way to implement Stripe payment is to redirect the visitor to the Stripe Checkout and it can handle the payment processing. Now, let’s add the payment view to the app/views.py

				
					# New imports
from django.conf import settings # new
from django.urls import reverse # new
from django.utils import timezone # new
import stripe # new

# Set the stripe api key
stripe.api_key = settings.STRIPE_SECRET_API_KEY

def buy_now(request, product_id):
    try:
        product = get_object_or_404(Product, pk=product_id)
        
        order = Order.objects.create(
            product=product,
            quantity=1,
        )
        
        # Create a Stripe checkout session, passing in the product data
        checkout_session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=[
                {
                    'price_data': {
                        'currency': 'usd',  # Specify the currency here
                        'product_data': { 
                            'name': product.name,
                            'description': product.description,
                        },
                        'unit_amount': int(product.price * 100), # Convert the original price to cents
                    },
                    'quantity': 1,
                },
            ],
            mode='payment', # use it for one time payment
            success_url=request.build_absolute_uri(reverse('payment_success', args=[order.pk])),
            cancel_url=request.build_absolute_uri(reverse('payment_cancel', args=[order.pk])),
            metadata={
                'order_id': order.pk,
                'product_id': product.pk,
            },
        )
        
        # To learn more check out the official documentation https://docs.stripe.com/checkout/quickstart
        
        # Redirect the user to the Stripe checkout page
        return redirect(checkout_session.url, code=303)

    except Product.DoesNotExist:
        return redirect('payment_list')

# Page to be redirected if the payment is successful
def payment_success(request, order_id):
    order = get_object_or_404(Order, pk=order_id)
    
    # Update the order status to "paid"
    order.paid = True
    order.paid_at = timezone.now()
    order.save()
    return render(request, 'payment_success.html', {'order': order})

# Page to be redirected if the payment is canceled
def payment_cancel(request, order_id):
    order = get_object_or_404(Order, pk=order_id)
    return render(request, 'payment_cancel.html', {'order': order})
				
			

Now, let’s add the urls of these views:

app/urls.py

				
					urlpatterns = [
    # new urls
    path('success/<int:order_id>', views.payment_success, name='payment_success'),
    path('cancel/<int:order_id>', views.payment_cancel, name='payment_cancel'),
]
				
			

Next, let’s create the app/templates/payment_success.html and app/templates/payment_cancel.html

payment_success.html

				
					{% extends "base.html" %}

{% block title %}Payment Successful{% endblock %}

{% block content %}
<div class="container">
    <div class="alert alert-success text-center mt-5">
        <h1>Payment Successful!</h1>
        <p>Thank you for your purchase. Your order has been placed successfully.</p>
        <hr>
        <h3>Order Details</h3>
        <p><strong>Product:</strong> {{ order.product.name }}</p>
        <p><strong>Quantity:</strong> {{ order.quantity }}</p>
        <p><strong>Total Price:</strong> ${{ order.total_price }}</p>
        <p><strong>Order ID:</strong> {{ order.id }}</p>
        <p>We will send you an email with further instructions.</p>
        <a href="{% url 'product_list' %}" class="btn btn-primary mt-3">Back to Store</a>
    </div>
</div>
{% endblock %}
				
			

payment_cancel.html

				
					{% extends "base.html" %}

{% block title %}Payment Cancelled{% endblock %}

{% block content %}
<div class="container">
    <div class="alert alert-warning text-center mt-5">
        <h1>Payment Cancelled</h1>
        <p>Your payment has been cancelled. If you have any issues, please try again or contact support.</p>
        <hr>
        <a href="{% url 'product_list' %}" class="btn btn-primary mt-3">Back to Store</a>
    </div>
</div>
{% endblock %}
				
			

Next, we need to link the Buy Now button to the buy_now url with the product id as a parameter, so let’s update the product_detail.html file

				
					{% extends "base.html" %}

{% block title %}{{ product.name }} Details{% endblock %}

{% block content %}
<div class="container">
    <div class="row">
        <div class="col-md-6">
            {% if product.image %}
            <img decoding="async" src="{{ product.image_url }}" class="img-fluid rounded" alt="{{ product.name }}">
            {% else %}
            <img decoding="async" src="https://via.placeholder.com/400" class="img-fluid rounded" alt="Placeholder image">
            {% endif %}
        </div>
        <div class="col-md-6">
            <h1>{{ product.name }}</h1>
            <p class="lead">{{ product.description }}</p>
            <p class="h4"><strong>Price:</strong> ${{ product.price }}</p>
            <div class="mt-4">
                <a href="{% url 'buy_now' product.id %}" class="btn btn-primary">Buy Now</a>
                <a href="{% url 'product_list' %}" class="btn btn-secondary">Back to Products List</a>
            </div>
        </div>
    </div>
</div>
{% endblock %}
				
			

Now, if you click the Buy Now button, you’ll be redirected to the stripe checkout where you can enter your email and the card details with, to test the payment integration use this link to get test card numbers.


When ever the user clicks the Buy Now button an order record after the payment is successful, the user will be redirected to the Success url and if canceled it’ll redirect to the Cancel url.

Conclusion

Integrating Stripe into your Django application can greatly enhance its functionality, allowing you to accept payments securely and efficiently. With its robust API and developer-friendly tools, Stripe makes it easy to build a seamless checkout experience for your users.

In this guide, we’ve walked through the steps to set up a basic product and order management system, display product listings and details, and implement Stripe Checkout for payments. You can use this foundation to expand your project with additional features, such as user authentication, order history, and more advanced payment options like subscriptions.

Stripe’s comprehensive documentation and developer resources are excellent for exploring its capabilities further. Whether you’re working on a small project or a full-scale eCommerce platform, Stripe is a powerful tool to meet your payment needs.

If you found this guide helpful, feel free to share it with others. Stay tuned for more Django tutorials and happy coding!

Leave a Reply

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

Copyright © 2026. All rights reserved