Search code examples
pythondjangodjango-viewsstripe-payments

Can't redirect to success page in Django + Stripe project


I'm developing my first test Django Stripe project, but I'm currently stuck at the point because the redirect on success page is not working.

This is my views.py file

import stripe
from django.conf import settings
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.views import View
from django.views.generic import TemplateView

from .models import Item

stripe.api_key = settings.STRIPE_SECRET_KEY


class ProductLandingPageView(TemplateView):
    template_name = 'landing.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        item_id = self.kwargs["id"]
        item = get_object_or_404(Item, id=item_id)
        context['item'] = item
        return context



class CreateCheckoutSessionView(View):
    def get(self, request, *args, **kwargs):
        item_id = self.kwargs["id"]
        DOMAIN: str = 'http://127.0.0.1:8000'
        item = Item.objects.get(id=item_id)
        session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=[
                {
                    'price_data': {
                        'currency': 'usd',
                        'unit_amount': item.price * 100,
                        'product_data': {
                            'name': item.name,
                        },
                    },
                    'quantity': 1,
                },
            ],
            payment_intent_data={
                'metadata': {
                    'item_id': item.id,
                },
            },
            mode='payment',
            success_url=DOMAIN + '/success/',
            cancel_url=DOMAIN + '/cancel/',
        )
        return HttpResponse(session.id)


class SuccessView(TemplateView):
    template_name = "success.html"


class CancelView(TemplateView):
    template_name = "cancel.html"

And this is my template.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Homepage</title>
    <script src="https://js.stripe.com/v3/"></script>
</head>
<body>
    <div class="description">
        <h3>{{ item.name }}</h3>
        <h5>{{ item.display_price }} USD.</h5>
    </div>
    <button id="buy-button" data-item-id="{{ item.id }}">Buy</button>



    <script>
    document.getElementById('buy-button').addEventListener('click', function() {
  var itemId = this.getAttribute('data-item-id');
  fetch('/buy/' + itemId)
    .then(function(response) {
      return response.json();
    })
    .then(function(data) {
      var stripe = Stripe(data.stripe_public_key);
      stripe.redirectToCheckout({ sessionId: data.session_id });
    })
    .catch(function(error) {
      console.error('Ошибка:', error);
    });
});
  </script>

</body>
</html>

I'm using env variables for keys so added these lines in settings

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

And my urls.py is set this way

from api.views import CancelView, SuccessView, CreateCheckoutSessionView, ProductLandingPageView
from django.contrib import admin
from django.urls import path

urlpatterns = [
path('admin/', admin.site.urls),
path('item/<int:id>', ProductLandingPageView.as_view(), name='item'),
path('buy/<int:id>', CreateCheckoutSessionView.as_view(), name='buy'),
path('cancel/', CancelView.as_view(), name='cancel'),
path('success/', SuccessView.as_view(), name='success'),]

Project structure

enter image description here

Do you have any suggestions on how to solve the issue? BTW if you notice any other thing to improve - please feel free to comment it. I'm very new to stripe service and still learning how it works.

UPD:

Problem solved by modifying JS code as follows

<script>
    document.getElementById('buy-button').addEventListener('click', function() {
  var itemId = this.getAttribute('data-item-id');
  var stripe = Stripe("{{ STRIPE_PUBLIC_KEY }}");
  fetch('/buy/' + itemId)
    .then(function(response) {
      return response.json();
    })
    .then(function (session) {
      return stripe.redirectToCheckout({ sessionId: session.id });
    })
    .catch(function(error) {
      console.error('Ошибка:', error);
    });
});
</script>

Solution

  • In general you have two options to do the Checkout Session redirect.

    Option 1:

    • Create a Checkout Session on the backend and send the checkout.url to your frontend
    • Then on the frontend do the redirection with window.location.href

    Option 2:

    • Have a form on your frontend, something like <form action="/checkout-session" method="POST"> <button type="submit" /> </form>
    • On the backend, the route /checkout-session creates a Checkout Session and return a 303 redirect with the Checkout Session url