【Django】Stripe APIでオンライン決済機能を実装する方法|PythonでWebアプリ構築

こんにちは、DXCEL WAVEの運営者(@dxcelwave)です!

本記事読了後以下ができるようになります
  • Python Djangoフレームワーク上にStripe APIを活用したオンライン決済機能を導入する
  • Djanogoでオンライン決済画面を実装する
  • 顧客が商品を購入したタイミングで通知を受け取る
  • Django DBで商品購入履歴を管理する
目次

【Django】Stripeを用いたオンライン決済機能の導入概要

本記事では、上記動画に示すようなオンライン決済画面をDjangoフレームワークで実装する方法について解説します。オンライン決済機能導入に際して、Stripeが提供する決済APIを活用します。

Stripeとは

【Stripe公式】https://stripe.com/jp

stripe(ストライプ)とは、アメリカ(サンフランシスコ)とアイルランド(ダブリン)に本社を置く、オンライン決済サービスを提供するSaaS企業です。

eコマースWebサイトやモバイルアプリ向けに、多様な決済処理アプリケーションを提供しています。また、開発者向けにAPIも提供しています。

stripeの決済サービスを活用することで具体的に次のようなことができるようになります。

  • eコマースWebサイトやモバイルアプリ向けオンライン決済画面の簡易作成
  • サブスクリプション機能の構築
  • 決済リンクの簡易作成
  • オンライン請求書の発行・管理

stripe API活用によるDjango決済機能実装アーキテクチャ

本記事ではStripeドキュメント(構築済みチェックアウト画面)をDjangoで実装する方法について解説します。

その際、全体のアーキテクチャ像は上記になる想定です。

アーキテクチャポイント
  • Django Viewでは、Stripe APIを呼び出す仕組み構築
  • Django ViewからPUTリクエストを受け取ったStripeは、オンライン決済サービスを提供
  • 顧客は、Django Viewを経由してStripeオンライン決済(商品購入)が可能に
  • Stripeオンライン決済後、顧客の購買履歴をDjango DBが受け取りDBにて管理

【事前準備】Stripeオンライン決済機能導入前のDjango環境設定

Stripeのオンライン決済機能を実装するために、Django環境を構築していきます。

以下のタスク事項を事前に対応しておきましょう。以下1つずつ対応方法を解説します。

事前要対応タスク一覧
  • Pythonライブラリのインストール
  • Djangoプロジェクト・アプリケーションの構築
  • stripeアカウントを作成
  • stripeパブリックキーとシークレットキーを取得

Pythonライブラリのインストール

本記事では以下に示すバージョンのPythonライブラリを利用していきます。

  • asgiref==3.4.1
  • Django==4.0.3
  • pytz==2021.1
  • sqlperse==0.4.2
  • stripe==3.5.0

Djangoのバージョンは4.0.0以降を活用するようにしましょう。

DjangoからstripeのAPIを呼び出すには、stripeライブラリの利用が必須です。インタラクティブシェル(Macはターミナル、Windowsはコマンドプロンプト)を開き、以下を実行しましょう。

pip3 install stripe

Djangoプロジェクト・アプリケーションの構築

本記事ではDjangoプロジェクトフォルダ(Project_Folder)とアプリケーションフォルダ(App_Folder)を用意した上記フォルダ構成を初期設定として利用します。

Djangoプロジェクトおよびアプリケーションは、以下記事を参考にしながら構築しましょう。

stripeアカウントを作成・APIキーの取得

DjangoでStripeのオンライン決済機能を実装する場合、事前にstripeアカウントを作成し、APIキーを取得しておく必要があります。以下の記事を参考にし、APIキーを取得しましょう。

後続で活用するAPIキー

  • テスト環境用のAPIキー(パブリックキー)
  • テスト環境用のシークレットキー(テストキー)

APIキーの取得手順

【実践】stripeオンライン決済機能をDjangoで実装する方法

ここから実際にDjangoフレームワークからStripe APIを呼び出し、オンライン決済機能を活用するに至るまでの方法を解説していきます。

以下手順に沿ってPythonコーディング概要と方法をそれぞれ詳しく解説していきます。

  1. settings.pyの設定
  2. データベース設定
  3. 画面表示設定(views.py)
  4. 画面表示設定(urls.py)
  5. フロント画面作成(HTML)
  6. フロント画面作成(CSS)
  7. 動作確認

settings.pyの設定

はじめに、Project_Folder > settings.pyにコードを修正していきます。

以下の手順に沿って作業を進めましょう。

データベース設定

続いてデータベース設定を行うために、App_Folder > models.py, admin.pyにコードを記載していきます。

画面表示設定|views.py

続いてWebアプリ画面の表示設定を行うために、App_Folder > views.pyを修正していきます。

以下のコードに書き換えましょう。

views.pyコード全量

import json
import stripe
from django.conf import settings
from django.http import JsonResponse, HttpResponse
from django.shortcuts import redirect
from django.core.mail import send_mail
from django.views.generic import TemplateView
from django.views.generic import ListView
from django.views.decorators.csrf import csrf_exempt
from django.views import View
from .models import Product
from .models import Price


# STRIPEのシークレットキー
stripe.api_key = settings.STRIPE_SECRET_KEY

# WEBHOOKのシークレットキー
endpoint_secret = settings.STRIPE_WEBHOOK_SECRET

# 決済成功画面
class SuccessPageView(TemplateView):
    template_name = 'success.html'

# 決済キャンセル画面
class CancelPageView(TemplateView):
    template_name = 'cancel.html'

class ProductTopPageView(ListView):
    # 商品マスタ
    model = Product
    # ページリンク
    template_name = "product-top.html"
    #レコード情報をテンプレートに渡すオブジェクト
    context_object_name = "product_list"


# 決済画面
class CreateCheckoutSessionView(View):

    def post(self, request, *args, **kwargs):
        # 商品マスタ呼出
        product = Product.objects.get(id=self.kwargs["pk"])
        price   = Price.objects.get(product=product)

        # ドメイン
        YOUR_DOMAIN = "http://127.0.0.1:8000"
        # 決済用セッション
        checkout_session = stripe.checkout.Session.create(
            # 決済方法
            payment_method_types=['card'],
            # 決済詳細
            line_items=[
                {
                    'price': price.stripe_price_id,       # 価格IDを指定
                    'quantity': 1,                        # 数量
                },
            ],
            # POSTリクエスト時にメタデータ取得
            metadata = {
                        "product_id":product.id,
                       },
            mode='payment',                               # 決済手段(一括)
            success_url=YOUR_DOMAIN + '/success/',        # 決済成功時のリダイレクト先
            cancel_url=YOUR_DOMAIN + '/cancel/',          # 決済キャンセル時のリダイレクト先
        )
        return redirect(checkout_session.url)

【参考】views.pyコード個別解説

上記のコードについて1つずつ解説していきます。

画面表示設定|urls.py

続いてWebアプリ画面の表示設定を行うために、Project_Folder > urls.pyを修正していきます。

以下のコードに書き換えましょう。

from django.contrib import admin
from django.urls import path
from django.conf import settings            # settings.pyの変数
from django.conf.urls.static import static  # メディア表示

# App_Folderからviews.pyで定義した関数呼出
from App_Folder.views import (
    CreateCheckoutSessionView,
    ProductTopPageView,
    SuccessPageView,
    CancelPageView,
    )

urlpatterns = [
    path('admin/', admin.site.urls),                                                                               # 管理画面
    path("", ProductTopPageView.as_view(), name="product-top-page"),                                               # 商品トップ
    path("create-checkout-session/<pk>/", CreateCheckoutSessionView.as_view(), name="create-checkout-session"),    # 個別商品決済画面
    path("success/", SuccessPageView.as_view(), name="success"),                                                   # 決済成功時にリダイレクト先
    path("cancel/", CancelPageView.as_view(), name="cancel"),                                                      # 決済キャンセル時のリダイレクト先
]

# メディア表示
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

フロント画面作成|HTML

フロント画面のHTMLファイルにコードを記述します。Template直下の3つのファイルが対象です。

htmlファイル名概要
product-top.html商品のトップ画面
success.htmlStripeで決済が完了した際にリダイレクトされる画面
cencel.htmlStripeで決済キャンセルした際にリダイレクトされる画面

各種HTMLファイルに記述するコード

【参考】テンプレートの概要はこちらの記事で詳しく解説しています。

フロント画面作成|CSS

static > style.cssファイルにCSSコードを記述します。

上記、デザインコード例を参考にしましょう。コードはそのまま活用いただくこともできます。

動作確認

python3 manage.py runserver

ここまでできましたら一度動作確認を行いましょう!

ローカルサーバーを立ち上げ決済画面を開きテスト商品を購入してみましょう。

この時、カード番号は4242 4242 4242 4242と入力します。

Stripe Webhookをもとに顧客支払通知を受け取りDBに登録する

ここまでで「Stripe APIを活用した決済機能の導入」と「商品決済画面の作成」が完了しました。ここからは「顧客が商品を購入したタイミングで通知を受け取り、支払い履歴をDjango DB上に保存して管理する方法」について解説します。

StripeではWebhookという方法が利用されています。Webhookとは、オンライン決済が完了したタイミングで、StripeがそのイベントをHTTPのPOSTメソッドで送ってくれるものです。

このWebhookで顧客の商品購入イベントを検知したり、StripeからのレスポンスをDBに保存することで顧客の支払い履歴が管理できるようになります。

【事前準備】Stripe CLIをインストールする

Webhookの利用には、Stripe ILCのインストールが必要です。

イベントハンドラ・DB管理関数を作成|views.py

このセクションでは、顧客の購入イベント(checkout.session.completed)をStripeから受信するイベントハンドラ関数をviews.pyに追加します。さらに、Stripeから受信したレスポンスをDBに保存する関数も併せて作成します。

イベントハンドラ関数とDB管理関数を追記したviews.pyを以下に示します。

stripe_webhookおよびSaveTransactionが主な更新点になっています。

【全量コード】views.py

import json
import stripe
from django.conf import settings
from django.http import JsonResponse, HttpResponse
from django.shortcuts import redirect
from django.core.mail import send_mail
from django.views.generic import TemplateView
from django.views.generic import ListView
from django.views.decorators.csrf import csrf_exempt
from django.views import View
from .models import Product
from .models import Price
from .models import Transaction # 追加
import datetime   # 追加


# STRIPEのシークレットキー
stripe.api_key = settings.STRIPE_SECRET_KEY

# WEBHOOKのシークレットキー
endpoint_secret = settings.STRIPE_WEBHOOK_SECRET

# 決済成功画面
class SuccessPageView(TemplateView):
    template_name = 'success.html'

# 決済キャンセル画面
class CancelPageView(TemplateView):
    template_name = 'cancel.html'

class ProductTopPageView(ListView):
    # 商品マスタ
    model = Product
    # ページリンク
    template_name = "product-top.html"
    #レコード情報をテンプレートに渡すオブジェクト
    context_object_name = "product_list"


# 決済画面
class CreateCheckoutSessionView(View):

    def post(self, request, *args, **kwargs):
        # 商品マスタ呼出
        product = Product.objects.get(id=self.kwargs["pk"])
        price   = Price.objects.get(product=product)

        # ドメイン
        YOUR_DOMAIN = "http://127.0.0.1:8000"
        # 決済用セッション
        checkout_session = stripe.checkout.Session.create(
            # 決済方法
            payment_method_types=['card'],
            # 決済詳細
            line_items=[
                {
                    'price': price.stripe_price_id,       # 価格IDを指定
                    'quantity': 1,                        # 数量
                },
            ],
            # POSTリクエスト時にメタデータ取得
            metadata = {
                        "product_id":product.id,
                       },
            mode='payment',                               # 決済手段(一括)
            success_url=YOUR_DOMAIN + '/success/',        # 決済成功時のリダイレクト先
            cancel_url=YOUR_DOMAIN + '/cancel/',          # 決済キャンセル時のリダイレクト先
        )
        return redirect(checkout_session.url)




# イベントハンドラ
@csrf_exempt
def stripe_webhook(request):

    # サーバーのイベントログからの出力ステートメント
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    event = None
    try:
        event = stripe.Webhook.construct_event(payload, sig_header, endpoint_secret)
    except ValueError as e:
        # 有効でないpayload
        return HttpResponse(status=400)
    except stripe.error.SignatureVerificationError as e:
        # 有効でない署名
        return HttpResponse(status=400)

    # checkout.session.completedイベント検知
    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']

        # イベント情報取得
        customer_name  = session["customer_details"]["name"]     # 顧客名
        customer_email = session["customer_details"]["email"]    # 顧客メール
        product_id     = session["metadata"]["product_id"]       # 購入商品ID
        product        = Product.objects.get(id=product_id)      # 購入商品情報
        product_name   = product.name                            # 購入した商品名
        amount         = session["amount_total"]                 # 購入金額(手数料抜き)

        # DBに結果を保存
        SaveTransaction(product_name, customer_name, customer_email, amount)


        # 決済完了後メール送信(Djangoのメール機能利用)
        send_mail(
            subject = '商品購入完了!',                                                                                     # 件名
            message = '{}様\n商品購入ありがとうございます。購入された商品URLはこちら{}'.format(customer_name,product.url),  # メール本文
            recipient_list = [customer_email],                                                                              # TO
            from_email = 'test@test.com'                                                                                    # FROM
        )
        # 結果確認
        print(session)

    return HttpResponse(status=200)


# 顧客の商品購入履歴を保存
def SaveTransaction(product_name, customer_name, customer_email, amount):
    # DB保存
    saveData = Transaction.objects.get_or_create(
                        product_name   =  product_name,
                        date           = datetime.datetime.now(),
                        customer_name  = customer_name,
                        email          = customer_email,
                        product_amount = amount
                        )
    return saveData

【コード個別解説】views.py

画面の表示設定|urls.py

Project_Folder > urls.pyを開き、webhookのurlを追加します。以下のコードに書き換えましょう。

from django.contrib import admin
from django.urls import path
from django.conf import settings            # settings.pyの変数
from django.conf.urls.static import static  # メディア表示

# App_Folderからviews.pyで定義した関数呼出
from App_Folder.views import (
    CreateCheckoutSessionView,
    ProductTopPageView,
    SuccessPageView,
    CancelPageView,
    stripe_webhook,
    )

urlpatterns = [
    path('admin/', admin.site.urls),                                                                               # 管理画面
    path("", ProductTopPageView.as_view(), name="product-top-page"),                                               # 商品トップ
    path("create-checkout-session/<pk>/", CreateCheckoutSessionView.as_view(), name="create-checkout-session"),    # 個別商品決済画面
    path("success/", SuccessPageView.as_view(), name="success"),                                                   # 決済成功時にリダイレクト先
    path("cancel/", CancelPageView.as_view(), name="cancel"),                                                      # 決済キャンセル時のリダイレクト先
    path("webhook/", stripe_webhook, name="webhook"),                                                              # 追加 Webhook
]

# メディア表示
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Webhookのシークレットキーを取得

Stripeに「このPCのlocalhost:8000/webhook/に情報を転送して」という命令を伝える作業を行います。このようにローカルのURLを設定するとこで、イベントハンドラが取得したイベント情報をローカルPCから簡単に確認することができるようになります。

前述でCLIにログインしたインタラクティブシェルに対して以下を入力し実行しましょう。

stripe listen --forward-to localhost:8000/webhook/

上記を入力すると、次のような出力結果が得られます。その中にWebhookシークレットキーが表示されていますため、お手元にメモしましょう。

Ready! You are using Stripe API Version [2020-08-27]. 
Your webhook signing secret is 'xxxxx WEBHOOKシクレットキーxxxxxx' (^C to quit)

Webhookシークレットキーを登録|settings.py

前述で取得したWebhookのシークレットキーをsettings.pyに追記します。以下の部分を更新しましょう。

# Stripeのパブリックキー
STRIPE_PUBLIC_KEY = 'ここにSTRIPE_PUBLIC_KEYを入力'

# Stripeのシークレットキー
STRIPE_SECRET_KEY = 'ここにSTRIPE_SECRET_KEYを入力'

# StripeのWebhookのシークレットキー
STRIPE_WEBHOOK_SECRET = 'ここにSTRIPE_WEBHOOK_SECRETを入力'

データベース設定|models.py・admin.py

Stripeオンライン決済画面で商品を購入した顧客のイベントを検知し、Django DBに情報を保存するための設定を以下行っていきます。

動作確認

ターミナルまたはコマンドプロンプト上で商品支払い履歴を確認

Stripe決済画面からテスト商品を購入してみましょう。

購入後、「LCIにログインしたインタラクティブシェル」と「ローカルサーバーを立ち上げたインタラクティブシェル」それぞれの出力結果で以下が得られていれば、正常に動作していることを意味します。

Django DBで商品支払い履歴を確認

最後に、Django管理画面を開きTransactionsテーブルの中身を確認しましょう。

上記のように、Stripeオンライン決済画面で決済完了した履歴がレコードとして登録されていれば正常動作と判断します。

【まとめ】Stripe×Djangoでオンライン決済機能の導入

これにてStripeのオンライン決済機能をDjangoで導入するプロセスは全て完了です!

本番運用を見越したアプリ実装は、APIキーを本番用に書き換え、商品も本番用に登録し直すだけで簡単に対応することができます。

【参考】本記事で紹介したコードのgithubレポジトリ

本記事で紹介したコードは以下のgithubレポジトリに格納しています。適時参照下さい。

Githubリンク:https://github.com/dxcelwave/django-stripe-onlinepayment/tree/main

【参考】Djangoの解説記事一覧

最後までご覧いただきありがとうございました。当サイトではDjangoフレームワークを用いた解説記事を多数取り扱っております。次のように体系的に整理しておりますため学習にお役立て下さい。

Djangoおすすめ学習教材

Djangoを学習したい方向けに厳選したおすすめ教材も紹介しています。是非ご覧下さい。

Django Framework活用のWebアプリ開発記事

#記事タイトルレベル
1【Django】開発環境構築|プロジェクト・アプリ開発のチュートリアル★☆☆
2【Django】MVC・MVTアーキテクチャ・モデル設計思考★☆☆
3【Django】URLマッピングの設定方法(urls.py)★☆☆
4-1【Django】テンプレート(Template)の作成・HTML/CSSファイルの取り扱い★☆☆
4-2【Django】JavaScriptをテンプレートから読み込む★☆☆
5【Django】テンプレートタグ概要|フロント画面設計★☆☆
6【Django】モデルの作成・操作(models.py)・データベース操作★☆☆
7【Django】スーパーユーザの作成・管理画面からデータベース操作(admin.py)★☆☆
8【Django】お問い合わせフォーム(forms.py)作成方法★☆☆
9【Django】モデル連携のお問い合わせフォーム作成方法(ModelForm)★☆☆
10【Django】認証画面(1) アカウント新規登録画面の作成方法★★☆
11【Django】認証画面(2) ログイン画面の作成方法★★☆
12【Django】クラスベースビュー(Class-based View)の操作方法★☆☆
13【Django】テンプレートビュー(TemplateView)の操作方法★☆☆
14【Django】リストビュー(ListView)の操作方法★★☆
15【Django】詳細ビュー(DetailView)の操作方法★★☆
16【Django】ViewクラスでデータベースのCRUD操作(作成・読込・更新・削除)★★☆
応用【Django】Stripe APIを活用したオンライン決済機能・商品購入画面の実装★★★

Django REST framework活用のWeb API開発記事

#記事タイトルレベル
1Django REST frameworkを用いてWeb APIを実装★★☆

この記事が気に入ったら
フォローしてね!

本記事をシェア!
目次