【Django】Stripeの決済機能を実装する方法【Payment Intent API】

アイキャッチ画像
  • DjangoでStripeの決済機能を実装する方法とは?
  • StripeのPayment Intentの使い方とは?

本記事ではこのような疑問を解決します。


Webアプリを開発する際に、決済機能の実装はほぼマストです。

そんな決済機能の実装でよく使われるのがStripeという決済プラットフォームです。

ではDjangoでのWebアプリ開発においてStripeの決済機能を実装するにはどのような手順を踏めばいいのでしょうか。

ネット上でもDjango×Stripeの記事は存在しますが、日本語でわかりやすく解説されている記事はまだまだ少ない印象です。

そこで今回はDjangoでStripeの決済機能を実装する方法を解説していきます。

Stripeでの決済機能の実装にはPayment Intent APIを使用する

今回実装するStripeの決済機能ではPayment IntentというAPIを使用します。

Payment Intent APIはすべてのStripe製品と支払い方法を統合するAPIとして設計されたものです。

Payment Intent APIとよく比較されるのがCharges APIですが、以下の理由でPayment Intent APIを使用することが推奨されています。

・Stripeでは今後、Charges APIを廃止する予定はないが、新機能を使用できるのはPayment Intents APIのみである

・Apple PayやGoogleペイはPayment Intent APIでのみ使用可能である

・支払いフォームのコンポーネントを利用できるElements Appearance APIは、Payment Intent APIでのみ使用可能である



※詳しくはStripe公式ドキュメントを参考にしてください。

そして、ネットでPayment Intent APIの使い方を検索すると、まだ日本語で説明されている記事は少ないようです。

さらにDjangoでの実装となるとなおさら少なくなります。

そのため、本記事はDjangoでPayment Intent APIを使用したい方のためになれば幸いです。

Stripeでの決済処理の流れ

まずはStripeでの決済処理の流れをユーザー側と開発者側で比較しながら確認しましょう。

ここではPayment Intent APIに基づいた流れになります。

①ユーザー側:支払い画面にアクセスする


①開発者側:
・バックエンド(views.py)
→Payment Intentを発行する

・フロントエンド(stripe.js)
→Payment Intentに紐づいたclient_secretを取得する
→Stripeインスタンスを作成する
→支払いフォームで使用するElementsを設定し、取得したclient secretを渡す
→Payment Elementを作成し、既存のDOM要素を、生成したDOM要素に置き換える

②ユーザー側:クレジットカード情報を入力し、支払い確定ボタンを押す


②開発者側:
・バックエンド(views.py)
→任意で支払い情報をDBに保存する

・フロントエンド(stripe.js)
→confirmPaymentで支払い処理を完了させる

③ユーザー側:支払い完了画面が表示される


③開発者側:
・バックエンド(views.py)
→支払い完了ページ等を表示する

Stripeでの決済機能の実装手順

それでは実際にStripeでの決済機能を実装していきましょう。

ここでは以下のDjangoプロジェクトを前提とし、Stripe決済機能に関係するファイルのみを操作します。

 sampleproject
 ├── sampleapp
 │   ├── __init__.py
 │   ├── admin.py
 │   ├── apps.py
 │   ├── migrations
 │   │   └── (中身省略)
 │   ├── models.py
 │   ├── tests.py
 │   └── views.py
 ├── sampleproject
 │   ├── __init__.py
 │   ├── __pycache__
 │   │   └── (中身省略)
 │   ├── asgi.py
 │   ├── settings.py
 │   ├── urls.py
 │   └── wsgi.py
 ├── templates
 │   ├── payment.html
 │   └── thanks.html
 ├── static
 │   ├── js
 │    ├── stripe.js
 └── manage.py 

バックエンド(Django)側の設定

DjangoでのStripe初期設定をする(settings.py)

#Stripeのダッシュボードからシークレットキーとパブリックキーをコピペする
STRIPE_API_KEY = 'Stripeのシークレットキー'
STRIPE_PUBLISHABLE_KEY = 'Stripeのパブリックキー'

URLを設定する(urls.py)

#①支払いフォームのページと②支払い完了後に表示するページのURLを設定する
urlpatterns = [
    path('payment/', views.payment, name="payment"),
    path('thanks/', views.thanks, name="thanks"),
]

支払いフォームを返す処理を記述する(views.py)

from django.conf import settings
import stripe

def payment(request):
    #StripeのAPIキーを登録する
    stripe.api_key = settings.STRIPE_API_KEY
    
    #今回は支払い額を10,000円とする
    amount=10000

    #PaymentIntentを作成する
    intent = stripe.PaymentIntent.create(
        amount=amount,
        currency='jpy',
        description='テスト支払い',
        payment_method_types=["card"],
    )
    
    #作成したPaymentIntentからclient_secretを取得する
    client_secret = intent["client_secret"]  
    
    #テンプレートと渡すデータを指定する
    template_name = "payment.html"
    context = {
        "amount": amount,
        "client_secret": client_secret,
    }

    return render(request, template_name, context)

クレジットカード情報が送信された後の処理を記述する(views.py)

#単純に支払い完了ページを表示する処理
def thanks(request):
    template_name = "thanks.html"
    return render(request, template_name)

フロントエンド(HTML・JavaScript)側の設定

支払いフォームのページを作成する(payment.html)

<!DOCTYPE html>
{% load static %}
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <script src="https://js.stripe.com/v3/"></script>    
    </head>
    <body>
        <!--inputタグでclient_secretを渡す→JavaScriptで値を取得する-->
        <input type="hidden" id="client_secret" value="{{ client_secret }}">
        
        <!--フォームが読み込まれたら、Payment Elementのインスタンスを作成して、それをコンテナーのDOMノードにマウントする-->
        <form id="payment-form">
            <div id="payment-element">
                <!-- Elements will create form elements here -->
            </div>
            <p>お支払い金額:{{ amount }}円</p>
            <button id="submit">支払いを確定する</button>
            <div id="error-message">
            <!-- Display error message to your customers here -->
            </div>
        </form>
        
        <script src="{% static 'js/stripe.js' %}"></script>
    </body>

支払い完了後に表示するページのファイルを作成する(thanks.html)

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <p>お支払い完了</p>
    </body>

Stripe処理を行うJavaScriptファイルを作成する(stripe.js)

// JavaScriptを使用して、client secretを取得する
const client_secret = document.getElementById('client_secret').value;

// JavaScriptを使用して、Stripeのインスタンスを作成する
const stripe = Stripe('Stripeのパブリックキー');

// 支払いフォームで使用するElementsを設定し、上で取得したclient secretを渡す
const elements = stripe.elements({
    clientSecret:client_secret,
    appearance:{
        theme: 'stripe',
    },
});

// Payment Elementを作成し、既存のDOM要素から生成したDOM要素に置き換える
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');

// id=payment-formの要素を取得する
const form = document.getElementById('payment-form');

// クレジットカード情報が送信された時の処理を記述する
form.addEventListener('submit', async (event) => {
  event.preventDefault();

  // confirmPaymentを呼び出して支払い処理を完了させる
  await stripe.confirmPayment({
    //`Elements` instance that was used to create the Payment Element
    elements,
    confirmParams: {
      return_url: '支払い完了後に呼び出すURL(ここでは/thanks)',
    },
  });
});

まとめ

以上がDjangoでStripeの決済機能を実装する方法になります。


一連の流れを一言でいうと、「Payment Intent APIを使ってclient secretの受け渡しにより決済処理を行なっていく」ということです。

ただ今回ご紹介した方法だと、このclient secretの受け渡しに少々セキュリティ面で問題があるかと思います。

本当はDjangoのrenderを使ってJavaScriptのfetchで受け取ることができればいいのですが、、、。

詳しい方がいらっしゃればコメントやメールにてご教授いただけると幸いです。

関連記事

Stripe Connectの仕組みとは?アカウントタイプと決済フローの関係とは? 本記事ではこのような疑問を解決します。本店と支店のように各エンドポイントでの支払いを中央で一括管理したいという場面ってありますよね。例えば、複数の子[…]

アイキャッチ画像

実務1年未満でもOK!フリーランスエンジニアの案件獲得方法はこちら!

必読

フリーランスエンジニアが案件獲得方法とは?自ら営業せずに案件を獲得するには?実務経験1年未満でも大丈夫なの? 本記事ではこのような疑問を解決します。これからフリーランスエンジニアとして独立したい方は、兎にも角にも案件の獲得が急務です[…]

アイキャッチ画像