5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Stripe】Djangoで作成したWebアプリにサブスクリプションを追加する

Posted at

webアプリに欲しい機能として決済機能が挙げられます。
今回はstripeで実装してみました。

実現したいこと

  • Djangoにサブスクリプション機能を追加する

前提条件

  • Djangoチュートリアルが完了していること

作業環境

  • OS
    • CentOS7
  • webサーバー
    • Nginx
  • 言語
    • Python
  • フレームワーク
    • Django

参考サイト

手順

  1. プロジェクト作成&アプリ作成
  2. stripeインストール
  3. カスタマーモデル追加
  4. サブスクリプションプラン作成
  5. チェックアウトセッション作成
  6. 支払いを行う

1. プロジェクト作成&アプリ作成

まずは今回使うライブラリをインストールしていきます。
ライブラリの移動がしやすいようにrequirements.txtを作成します

touch requirements.txt

今回使うライブラリを記述します。

requirements.txt
Django==3.1.4
stripe==2.56.0

ライブラリをインストールします。

pip install -r requirements.txt

プロジェクトを作成していきます。
django_stripeはプロジェクト名ですので、なんでもいいです。
同じにした方が後々分かりやすいと思います。

django-admin startproject django_stripe

アプリを追加します。

python manage.py startapp billing #請求って意味の英単語です

ここまでの作成で作業フォルダは以下のようになります。

.
├── billing
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── admin.cpython-39.pyc
│   │   └── models.cpython-39.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       └── __init__.cpython-39.pyc
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── db.sqlite3
├── django_stripe
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── settings.cpython-39.pyc
│   │   ├── urls.cpython-39.pyc
│   │   └── wsgi.cpython-39.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── requirements.txt

2. アプリインストール

インストールドアプリに先ほど作成したbillingアプリを追加します。

django_stripe/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'billing', #追加
]

3. カスタマーモデル追加

stripeで使うモデルを作成します。

billing/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.utils import timezone


class User(AbstractBaseUser):
    email = models.EmailField('メールアドレス', unique=True)
    password = models.CharField('パスワード',max_length=30)
    first_name = models.CharField('', max_length=30)
    last_name = models.CharField('', max_length=30)
    address = models.CharField('住所', max_length=30, blank=True)
    tel = models.CharField('電話番号', max_length=30, blank=True)
    created = models.DateTimeField('入会日',default=timezone.now)

class StripeCustomer(models.Model):
    user = models.OneToOneField(to=User, on_delete=models.CASCADE)
    stripeCustomerId = models.CharField(max_length=255)
    stripeSubscriptionId = models.CharField(max_length=255)

    def __str__(self):
        return self.user.username

4. サブスクリプションプラン作成

次はstripeでサブスクリプションのプランを作成していきます。
プランの作成方法は2種類あります。
・CLI
・公式サイト

今回は作成が簡単な公式サイトからプランを作成していきます。
以下のリンクからアクセスしてお好みのプランを作成してください。
https://dashboard.stripe.com/test/products/create

作成した後はAPI IDを忘れないようにメモしておきます。
後で必要になります。

5. チェックアウトセッション作成

次は支払い画面を作成していきます。
APIに必要なキーは以下から取得できます。
https://dashboard.stripe.com/test/apikeys

django_stripe/settings.py
# STRIPE 追加
STRIPE_PUBLIC_KEY = '公開可能キー'
STRIPE_SECRET_KEY = 'シークレットキー'
STRIPE_PRICE_ID = 'API_ID price_xxxxなやつ'
billing/views.py
from django.shortcuts import render
from django.conf import settings
from django.http.response import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from .models import User, StripeCustomer
from django.contrib.auth.decorators import login_required
import stripe

# 設定用の処理
@csrf_exempt
def stripe_config(request):
    if request.method == 'GET':
        stripe_config = {'publicKey': settings.STRIPE_PUBLIC_KEY}
        return JsonResponse(stripe_config, safe=False)

# 支払い画面に遷移させるための処理
@csrf_exempt
def create_checkout_session(request):
    if request.method == 'GET':
        domain_url = 'http://localhost:8000/billing/'
        stripe.api_key = settings.STRIPE_SECRET_KEY
        try:
            checkout_session = stripe.checkout.Session.create(
                client_reference_id=request.user.id if request.user.is_authenticated else None,
                success_url=domain_url + 'success?session_id={CHECKOUT_SESSION_ID}',
                cancel_url=domain_url + 'cancel/',
                payment_method_types=['card'],
                mode='subscription',
                line_items=[
                    {
                        'price': settings.STRIPE_PRICE_ID,
                        'quantity': 1,
                    }
                ]
            )
            return JsonResponse({'sessionId': checkout_session['id']})
        except Exception as e:
            return JsonResponse({'error': str(e)})

# 支払いに成功した後の画面
def success(request):
    return render(request, 'billing/success.html')

# 支払いに失敗した後の画面
def cancel(request):
    return render(request, 'billing/cancel.html')

この処理を呼び出すためのURLを作成します。

billing/urls.py
from django.urls import path
from accounts import views
from django.contrib import admin
from billing import views


urlpatterns = [
    path('', views.index, name='index'),
    path('config/', views.stripe_config),
    path('create-checkout-session/', views.create_checkout_session),
    path('success/', views.success),
    path('cancel/', views.cancel),
]

テンプレートを作成します。

billing/templates/billing/index.html
{% load static %}
<head>
  <title>Checkout</title>
  <script src="https://js.stripe.com/v3/"></script>
  <script src="{% static 'billing/js/stripe.js' %}"></script>
</head>
<body>
  <button id="checkout">Subscribe</button>
</body>
billing/templates/billing/success.html
success
billing/templates/billing/cancel.html
cancel

javascriptの処理を記述します。

billing/static/billing/js/stripe.js
console.log("Sanity check!");

// Get Stripe publishable key
fetch("/billing/config/")
    .then((result) => { return result.json(); })
    .then((data) => {
        // Initialize Stripe.js
        const stripe = Stripe(data.publicKey);

        // Event handler
        let submitBtn = document.querySelector("#checkout");
        if (submitBtn !== null) {
            submitBtn.addEventListener("click", () => {
                // Get Checkout Session ID
                fetch("/billing/create-checkout-session/")
                    .then((result) => { return result.json(); })
                    .then((data) => {
                        console.log(data);
                        // Redirect to Stripe Checkout
                        return stripe.redirectToCheckout({ sessionId: data.sessionId })
                    })
                    .then((res) => {
                        console.log(res);
                    });
            });
        }
    });

最終的なファイル構成は以下の通りです。

.
├── billing
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── admin.cpython-39.pyc
│   │   ├── models.cpython-39.pyc
│   │   ├── urls.cpython-39.pyc
│   │   └── views.cpython-39.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-39.pyc
│   │       └── __init__.cpython-39.pyc
│   ├── models.py
│   ├── static
│   │   └── billing
│   │       └── js
│   │           └── stripe.js #追加
│   ├── templates
│   │   └── billing
│   │       ├── cancel.html #追加
│   │       ├── index.html #追加
│   │       └── success.html #追加
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── db.sqlite3
├── django_stripe
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── settings.cpython-39.pyc
│   │   ├── urls.cpython-39.pyc
│   │   └── wsgi.cpython-39.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── requirements.txt

6. 支払いを行う

サーバーを起動させます

python manage.py runserver

(http://127.0.0.1:8000/billing)
アクセスするとボタンだけの画面になります。
ボタンをクリックするとstripeが用意してくれている支払い画面に遷移します。

後はテスト用のクレジットカード番号 4242 4242 4242 4242を入力します。

するとsuccessと表示されるページに遷移します。
これでサブスクリプションが完了になります。

質問や間違いなどありましたらコメントでお願いします。

参考サイト

5
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?