How to Integrate Stripe Payment Gateway in Python Django ?

Hi Dev,
This tutorial shows you how to integrate stripe payment gateway in python django. you can see stripe payment gateway integration with python django. I explained simply step by step stripe payment gateway integration with django app. you will learn stripe payment gateway integration with python django developer.
Here i explained simply step by step let's see bellow example I explained simply step by step stripe payment gateway integration with django app.
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....