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('/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.
{% block title %}{% endblock %} - My Store
{% block content %}
{% endblock %}
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 %}
Our Products
{% for product in products %}
{% if product.image %}
{% else %}
{% endif %}
{% endfor %}
{% endblock %}
product_detail.html
{% extends "base.html" %}
{% block title %}{{ product.name }} Details{% endblock %}
{% block content %}
{% if product.image %}
{% else %}
{% endif %}
{{ product.name }}
{{ product.description }}
Price: ${{ product.price }}
{% 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/', views.payment_success, name='payment_success'),
path('cancel/', 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 %}
Payment Successful!
Thank you for your purchase. Your order has been placed successfully.
Order Details
Product: {{ order.product.name }}
Quantity: {{ order.quantity }}
Total Price: ${{ order.total_price }}
Order ID: {{ order.id }}
We will send you an email with further instructions.
Back to Store
{% endblock %}
payment_cancel.html
{% extends "base.html" %}
{% block title %}Payment Cancelled{% endblock %}
{% block content %}
Payment Cancelled
Your payment has been cancelled. If you have any issues, please try again or contact support.
Back to Store
{% 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 %}
{% if product.image %}
{% else %}
{% endif %}
{{ product.name }}
{{ product.description }}
Price: ${{ product.price }}
{% 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!
