How to Integrate Stripe Payment Gateway in Python Django ?

Hello Developers,
Are you looking to integrate the Stripe payment gateway into your Python Django application? This comprehensive tutorial will guide you step by step through the process of setting up Stripe with Django. You'll learn how to configure your Django project, install and use the Stripe Python library, and securely process payments in your web application.
Whether you're a beginner or an experienced Django developer, this guide provides a clear and practical approach to Stripe payment integration. Follow the examples below to implement Stripe checkout and enhance your Django app with seamless online payment functionality.
Step 1 : Create a ProjectIn this step, we’ll create a new django project using the django-admin. Head back to your command-line interface and run the following command:
django-admin startproject exampleStep 2 : Create a App
python3 manage.py startapp paymentStep 3 : Update setting.py
In this step we require to do two things in our settings.py file, One is to change the path of template look up directory. Second one is to configure our media folder. Add the below lines to your settings.py file:
Next, you need to add it in the settings.py file as follows:
.... INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'payment', ]Step 4 : Database Setup
Next step, we will modify the settings.py file and update the database settings to configure the mydb database:
settings.pyDATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'example', 'USER':'root', 'PASSWORD':'root', 'HOST':'localhost', 'PORT':'3306' } }Step 5: Create Stripe Account
First you need to create account on stripe. then you can easily get account stripe publishable api key and a secret key.
Create Account from here: Stripe Dashboard.
Next you can get account key id and secret and add on settings.py file as like bellow:
setting.pyif DEBUG: STRIPE_PUBLISHABLE_KEY = 'test_publishable_key' STRIPE_SECRET_KEY = 'test_secret_key' # Uncomment these lines if you have a live keys # else: # STRIPE_PUBLISHABLE_KEY = 'production_publishable_key' # STRIPE_SECRET_KEY = 'production_secret_key'Step 6: Install Stripe Library
In this step, we need to install stripe package to use stripe api. so let's run bellow command:
pip install stripeStep 7: Create a Model
In this step we will require the database model for storing contacts.Open the payment/models.py file and add the following code:
payment/models.pyfrom django.db import models from django.core import validators # Create your models here. class Product(models.Model): id = models.BigAutoField( primary_key=True ) name = models.CharField( max_length=70, verbose_name='Product Name' ) description = models.TextField( max_length=800, verbose_name='Description' ) price = models.FloatField( verbose_name='Price', validators=[ validators.MinValueValidator(50), validators.MaxValueValidator(100000) ] ) class OrderDetail(models.Model): id = models.BigAutoField( primary_key=True ) # You can change as a Foreign Key to the user model customer_email = models.EmailField( verbose_name='Customer Email' ) product = models.ForeignKey( to=Product, verbose_name='Product', on_delete=models.PROTECT ) amount = models.IntegerField( verbose_name='Amount' ) stripe_payment_intent = models.CharField( max_length=200 ) # This field can be changed as status has_paid = models.BooleanField( default=False, verbose_name='Payment Status' ) created_on = models.DateTimeField( auto_now_add=True ) updated_on = models.DateTimeField( auto_now_add=True )
After creating these model, you need to create migrations using the following command:
Step 8 : Create a Migrationspython manage.py makemigrations
After successfully run the above command go to the payment/migrations/0001_initial.py
payment/migrations/0001_initial.pyimport django.core.validators from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Product', fields=[ ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=70, verbose_name='Product Name')), ('description', models.TextField(max_length=800, verbose_name='Description')), ('price', models.FloatField(validators=[django.core.validators.MinValueValidator(50), django.core.validators.MaxValueValidator(100000)], verbose_name='Price')), ], ), ]payment/migrations/0002_orderdetail.py
from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ ('payments', '0001_initial'), ] operations = [ migrations.CreateModel( name='OrderDetail', fields=[ ('id', models.BigAutoField(primary_key=True, serialize=False)), ('customer_email', models.EmailField(max_length=254, verbose_name='Customer Email')), ('amount', models.IntegerField(verbose_name='Amount')), ('stripe_payment_intent', models.CharField(max_length=200)), ('has_paid', models.BooleanField(default=False, verbose_name='Payment Status')), ('created_on', models.DateTimeField(auto_now_add=True)), ('updated_on', models.DateTimeField(auto_now_add=True)), ('product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='payments.product', verbose_name='Product')), ], ), ]
Next, you need to migrate your database using the following command:
python manage.py migrateStep 9 : Creating the Views
In this step, we need to create the views for performing fetch record to the database.Open the payment/views.py file and add:
payment/views.pyfrom django.http.response import HttpResponseNotFound, JsonResponse from django.shortcuts import get_object_or_404, render from django.urls import reverse, reverse_lazy from .models import * from django.views.generic import ListView, CreateView, DetailView, TemplateView import stripe from .forms import ProductForm from django.conf import settings from django.views.decorators.csrf import csrf_exempt import json # Create your views here. class ProductListView(ListView): model = Product template_name = "payments/product_list.html" context_object_name = 'product_list' class ProductCreateView(CreateView): model = Product form_class = ProductForm # fields = '__all__' template_name = "payments/product_create.html" success_url = reverse_lazy("home") class ProductDetailView(DetailView): model = Product template_name = "payments/product_detail.html" pk_url_kwarg = 'id' def get_context_data(self, **kwargs): context = super(ProductDetailView, self).get_context_data(**kwargs) context['stripe_publishable_key'] = settings.STRIPE_PUBLISHABLE_KEY return context @csrf_exempt def create_checkout_session(request, id): request_data = json.loads(request.body) product = get_object_or_404(Product, pk=id) stripe.api_key = settings.STRIPE_SECRET_KEY checkout_session = stripe.checkout.Session.create( # Customer Email is optional, # It is not safe to accept email directly from the client side customer_email = request_data['email'], payment_method_types=['card'], line_items=[ { 'price_data': { 'currency': 'inr', 'product_data': { 'name': product.name, }, 'unit_amount': int(product.price * 100), }, 'quantity': 1, } ], mode='payment', success_url=request.build_absolute_uri( reverse('success') ) + "?session_id={CHECKOUT_SESSION_ID}", cancel_url=request.build_absolute_uri(reverse('failed')), ) order = OrderDetail() order.customer_email = request_data['email'] order.product = product order.stripe_payment_intent = checkout_session['payment_intent'] order.amount = int(product.price * 100) order.save() # return JsonResponse({'data': checkout_session}) return JsonResponse({'sessionId': checkout_session.id}) class PaymentSuccessView(TemplateView): template_name = "payments/payment_success.html" def get(self, request, *args, **kwargs): session_id = request.GET.get('session_id') if session_id is None: return HttpResponseNotFound() stripe.api_key = settings.STRIPE_SECRET_KEY session = stripe.checkout.Session.retrieve(session_id) order = get_object_or_404(OrderDetail, stripe_payment_intent=session.payment_intent) order.has_paid = True order.save() return render(request, self.template_name) class PaymentFailedView(TemplateView): template_name = "payments/payment_failed.html"Step 10 : Creating the Templates
Here, in this step we need to create a new folder named payments in the templates folder of payments.
- base.html
- product_create.html
- product_detail.html
- payment_success.html
- payment_failed.html
- product_list.html
Here's the folder structure of payments app.
├── admin.py ├── apps.py ├── forms.py ├── __init__.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_orderdetail.py │ ├── __init__.py │ └── __pycache__ │ ├── 0001_initial.cpython-38.pyc │ ├── 0002_orderdetail.cpython-38.pyc │ └── __init__.cpython-38.pyc ├── models.py ├── __pycache__ │ ├── admin.cpython-38.pyc │ ├── apps.cpython-38.pyc │ ├── forms.cpython-38.pyc │ ├── __init__.cpython-38.pyc │ ├── models.cpython-38.pyc │ ├── urls.cpython-38.pyc │ └── views.cpython-38.pyc ├── templates │ └── payments │ ├── base.html │ ├── payment_failed.html │ ├── payment_success.html │ ├── product_create.html │ ├── product_detail.html │ └── product_list.html ├── tests.py ├── urls.py └── views.py 5 directories, 27 files
Next, open the payment/templates/base.html file and the add:
payment/templates/base.html<!doctype html> <html lang="en"> <head> <title>Django Payments App</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> <style type="text/css"> .success-animation { margin: 50px auto; } .checkmark { width: 100px; height: 100px; border-radius: 50%; display: block; stroke-width: 2; stroke: #4bb71b; stroke-miterlimit: 10; box-shadow: inset 0px 0px 0px #4bb71b; animation: fill 0.4s ease-in-out 0.4s forwards, scale 0.3s ease-in-out 0.9s both; position: relative; top: 5px; right: 5px; margin: 0 auto; } .checkmark__circle { stroke-dasharray: 166; stroke-dashoffset: 166; stroke-width: 2; stroke-miterlimit: 10; stroke: #4bb71b; fill: #fff; animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; } .checkmark__check { transform-origin: 50% 50%; stroke-dasharray: 48; stroke-dashoffset: 48; animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards; } @keyframes stroke { 100% { stroke-dashoffset: 0; } } @keyframes scale { 0%, 100% { transform: none; } 50% { transform: scale3d(1.1, 1.1, 1); } } @keyframes fill { 100% { box-shadow: inset 0px 0px 0px 30px #4bb71b; } } </style> </head> <body> {% block content %} {% endblock content %} <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script> </body> </html>
Next, open the payment/templates/product_create.html file and the add:
payment/templates/product_create.html{% extends 'payments/base.html' %} {% block content %} <div class="container mt-3"> <h1 class="text-center">Create Product</h1> <div class="row"> <div class="col-sm-6 offset-sm-3"> <form method="post" novalidate> {% csrf_token %} {{ form.as_p }} <div class="form-group"> <button type="submit" class="btn btn-primary">Save</button> <a href="{% url 'home' %}" class="btn btn-secondary">Back</a> </div> </form> </div> </div> </div> <script> document.querySelectorAll('input, textarea').forEach(e => { e.classList.add('form-control'); }) </script> {% endblock content %}
Next, open the payment/templates/product_list.html file and the add:
payment/templates/product_list.html{% extends 'payments/base.html' %} {% block content %} <div class="container mt-5"> <div class="row"> <div class="col-md-7 text-right"> <h1>Product List</h1> </div> <div class="col-md-5 text-right"> <a href="{% url 'create' %}" class="btn btn-success">Create Product</a> </div> </div> {% if product_list %} <div class="row"> {% for p in product_list %} <div class="col-sm-4"> <div class="card"> <img class="card-img-top" src="https://dummyimage.com/140x100.jpg?text={{ p.name }}" alt=""> <div class="card-body"> <h4 class="card-title">{{ p.name }}</h4> <p class="card-text">{{ p.description }}</p> </div> <div class="card-footer d-flex"> <a href="{% url 'detail' id=p.id %}" class="btn btn-success ml-auto">Buy Now</a> </div> </div> </div> {% endfor %} </div> {% else %} <div class="alert alert-info text-center mt-5"> The product list is empty. Please add some products first. </div> {% endif %} </div> {% endblock content %}
Next, open the payment/templates/product_detail.html file and the add:
payment/templates/product_detail.html{% extends 'payments/base.html' %} {% block content %} <div class="container mt-5 pt-5"> <div class="card"> <div class="card-header"> <h2>Product Detail</h2> </div> <div class="card-body"> <div class="container row"> <div class="col-md-2"> <img src="https://dummyimage.com/150x220.gif?text={{ object.name }}" alt=""> </div> <div class="col-md-10"> <h1>Name: {{ object.name }}</h1> <p>Description: {{ object.description }}</p> <p>Price: {{ object.price }}</p> <div class="form-group"> <label for="email">Email: </label> <input type="email" name="email" id="email" class="form-control" placeholder="Email"> <small>Please enter your email address</small> </div> </div> </div> </div> <div class="card-footer d-flex"> <a href="{% url 'home' %}" class="btn btn-secondary">Back to Home</a> <button class="btn btn-success ml-auto" id="checkout-button">Checkout</button> </div> </div> </div> <script src="https://js.stripe.com/v3/"></script> <script type="text/javascript"> // Create an instance of the Stripe object with your publishable API key var stripe = Stripe('{{ stripe_publishable_key }}'); var checkoutButton = document.getElementById('checkout-button'); checkoutButton.addEventListener('click', function () { var email = document.getElementById('email').value; if (email.length == 0) { alert("Please enter your email address."); return; } // Create a new Checkout Session using the server-side endpoint you // created in step 3. fetch("{% url 'api_checkout_session' id=object.id %}", { method: 'POST', body: JSON.stringify( { email: email } ) }) .then(function (response) { return response.json(); }) .then(function (session) { return stripe.redirectToCheckout({ sessionId: session.sessionId }); }) .then(function (result) { // If `redirectToCheckout` fails due to a browser or network // error, you should display the localized error message to your // customer using `error.message`. if (result.error) { alert(result.error.message); } }) .catch(function (error) { console.error('Error:', error); }); }); </script> {% endblock content %}
Next, open the payment/templates/payment_success.html file and the add:
payment/templates/payment_success.html{% extends 'payments/base.html' %} {% block content %} <div class="container mt-5"> <div class="jumbotron text-center mt-5"> <div class="success-animation"> <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"> <circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" /> <path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" /> </svg> <h1 class="text-success mt-3">Payment Successful</h1> </div> <p>Please wait while your payment is successfully confirmed and page is automatically redirect to your home page after few seconds..</p> </div> </div> <script type="text/javascript"> window.setTimeout( function() { window.location.reload(); window.location.href = "{% url 'home' %}"; }, 5000); </script> {% endblock content %}
Next, open the payment/templates/payment_failed.html file and the add:
payment/templates/payment_failed.html{% extends 'payments/base.html' %} {% block content %} <div class="container mt-5"> <div class="jumbotron text-center mt-5"> <h1 class="text-danger">Payment Failed</h1> <p>Please wait while your payment failure page is automatically redirect to your home page after few seconds..</p> </div> </div> <script type="text/javascript"> window.setTimeout( function() { window.location.reload(); window.location.href = "{% url 'home' %}"; }, 5000); </script> {% endblock content %}Step 11 : Creating URLs
In this section, we’ll create the urls to access our views.Go to the urls.py payment/urls.py file and update it as follows:
payment/urls.pyfrom django.urls import path from .views import * urlpatterns = [ path('', ProductListView.as_view(), name='home'), path('create/', ProductCreateView.as_view(), name='create'), path('detail/<id>/', ProductDetailView.as_view(), name='detail'), path('success/', PaymentSuccessView.as_view(), name='success'), path('failed/', PaymentFailedView.as_view(), name='failed'), path('api/checkout-session/<id>/', create_checkout_session, name='api_checkout_session'), ]
Next, we will require the modify the urls.py your root preoject folder lets update the file.
example/urls.pyfrom django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('payment.urls')), ]Run the Server
In this step, we’ll run the local development server for playing with our app without deploying it to the web.
python manage.py runserver
Next, go to the http://localhost:8000/ address with a web browser.
Product Checkout Page:

Payment Success Page:

We can check all these payment in Stripe dashboard

I Hope It will help you....
Frequently Asked Questions (FAQs)
What is Stripe and how does it work with Django?
Stripe is a payment processing platform that allows you to accept online payments. In Django, you can integrate Stripe using the Stripe Python SDK to securely handle transactions through forms or pre-built checkout pages.
How do I integrate Stripe payment gateway in Django?
To integrate Stripe in Django, install the Stripe library, configure your API keys in settings.py, and create views to handle payment sessions using Stripe Checkout or Payment Intents API.
Is Stripe free to use with Django for development?
Yes, Stripe is free for development and testing. You can use test API keys and test card numbers provided by Stripe to simulate real transactions.
What are the benefits of using Stripe in a Django app?
Stripe offers a secure and scalable solution for accepting online payments. It supports multiple payment methods, built-in fraud protection, and is easy to integrate with Django using the Stripe SDK.
Do I need a business account to use Stripe in Django?
To accept real payments, you will need to activate your Stripe account with business and bank details. However, for development and testing, a verified business account is not required.