• Skip to main content
  • Skip to primary sidebar

学習記録

DjangoでStripeを使用した月額課金方法

2021年5月29日 by 河副 太智 Leave a Comment

基本Django Stripe Subscriptionsを参考にする。

Contents

  • 1 model設定で以下のエラーが出た場合
  • 2 支払い完了画面に移行しない場合
  • 3 subscriptions_stripecustomerが無いというエラー
  • 4 stripe_webhookエラー
  • 5 NameError: name ‘request’ is not defined
  • 6 キャンセル処理
  • 7 メールアドレスの取得
  • 8 登録者にお礼のメール
  • 9 StripeAPIから取得できるデータ一覧
    • 9.1 event取得
      • 9.1.1 例:event取得後各種IDを取得
    • 9.2 顧客データ詳細を取得
      • 9.2.1 例:顧客データ詳細取得後各種情報を取得
    • 9.3 更に顧客データ詳細を表示
    • 9.4 HTMLにて上記データを表示
  • 10 ローカルでStripe CLI でwebhookをテスト

model設定で以下のエラーが出た場合

ERRORS:
subscriptions.StripeCustomer.user: (fields.E301) Field defines a relation with the model ‘auth.User’, which has been swapped out.
HINT: Update the relation to point at ‘settings.AUTH_USER_MODEL’.

参照サイトではDjango modelの仕様を前提としているのでエラーが出る
UserModelを使用する場合models.pyの記述方法を調整する必要がある。

subscriptions/models.pyに以下を記述する。

1
2
3
4
5
6
7
8
9
10
11
from django.conf import settings
from django.db import models
 
 
class StripeCustomer(models.Model):
    user = models.OneToOneField(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    stripeCustomerId = models.CharField(max_length=255)
    stripeSubscriptionId = models.CharField(max_length=255)
 
    def __str__(self):
        return self.user.username

 

 

支払い完了画面に移行しない場合

参照サイトではホームページ自体がStripeペイメントのページなので、
別のURLを設定する場合subscriptions/view.pyのurlを確認する

例えば以下の場合

success_url=domain_url + ‘success?session_id=
cancel_url=domain_url + ‘cancel/’,

以下に変更する

success_url=domain_url + ‘subscriptions/success?session_id=
cancel_url=domain_url + ‘subscriptions/cancel/’,

subscriptions_stripecustomerが無いというエラー

Stripe用のモデル(データベース)が設定されていない可能性がある。

python manage.py makemigrations subscriptions
python manage.py migrate subscriptions
を行う

stripe_webhookエラー

参照サイトではDjango modelの仕様を前提としているので
webhookでuser名の取得ができない。
user = User.objects.get(id=client_reference_id)にエラーが出る

カスタムユーザーモデルの場合上記のコードが動かないので
以下のモジュールをインポートしてコード内容をget_user_model()に変更する

from django.contrib.auth import get_user_model #インポートする

user = get_user_model().objects.get(id=client_reference_id)
ソース

NameError: name ‘request’ is not defined

ListViewにおいてStripeで支払った人にのみList内容を見せる場合で、
ListViewクラスの関数の引数がselfとなっている場合
stripe_customer = StripeCustomer.objects.get(user=request.user)で
上記エラーが出る。

その為”self.request.user”にする必要がある
stripe_customer = StripeCustomer.objects.get(user=self.request.user)

ソース

キャンセル処理

subscriptions/view.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@login_required
def cancel_subscription(request):
    if request.user.is_authenticated:
 
        stripe_customer = StripeCustomer.objects.get(user=request.user)
        stripe.api_key = settings.STRIPE_SECRET_KEY
        sub_id = stripe.Subscription.retrieve(stripe_customer.stripeSubscriptionId)
        print(sub_id)
        print(sub_id.id)
        user=request.user
        print("user is")
        print(user)
 
        try:
            #delete from stripeapi
            stripe.Subscription.delete(sub_id)
 
            #delete from StripeCustomer model
            StripeCustomer.objects.filter(stripeSubscriptionId=sub_id.id).delete()
            print('unsubscribed')
 
 
 
        except Exception as e:
            import traceback
            traceback.print_exc()
            return JsonResponse({'error': (e.args[0])}, status =403)
    
    return render(request, 'home.html')

メールアドレスの取得

1
2
3
4
5
session = event['data']['object']
stripe_customer_id = session.get('customer')
 
retrieve = stripe.Customer.retrieve(stripe_customer_id)
print(retrieve['email'])

登録者にお礼のメール

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        #メールアドレスの取得(その他名前などの追加情報も取得可)
        retrieve = stripe.Customer.retrieve(stripe_customer_id)
        print(retrieve['email'])
        customer_email = retrieve['email']
 
        subject = "Thank you for your subscription."
        message = "Here is your products"
        from_email = 'kawazoe@customslegaloffice.com'
        admin_email = ['kawazoe@customslegaloffice.com',customer_email ]
        print("send")
        try:
            send_mail(subject ,message, from_email, admin_email)
        except:
            import traceback
            traceback.print_exc()

StripeAPIから取得できるデータ一覧

event取得

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    stripe.api_key = settings.STRIPE_SECRET_KEY
    endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    event = None
    
 
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, endpoint_secret
        )
        print(event)
 
#以下取得できるデータ一覧
 
{
  "api_version": "2020-08-27",
  "created": 1623290218,
  "data": {
    "object": {
      "allow_promotion_codes": null,
      "amount_subtotal": 4,
      "amount_total": 4,
      "billing_address_collection": null,
      "cancel_url": "http://3.129.28.xxx/subscriptions/cancel/",
      "client_reference_id": "1",
      "currency": "jpy",
      "customer": "cus_Jduyyr093qeu2V",
      "customer_details": {
        "email": null,
        "tax_exempt": "none",
        "tax_ids": []
      },
      "customer_email": null,
      "id": "cs_test_a1eysaqK9Evwz4U85W30sPUo9COWcG96Akw5f3CnSKgmfT7qqVwijZixxx",
      "livemode": false,
      "locale": null,
      "metadata": {},
      "mode": "subscription",
      "object": "checkout.session",
      "payment_intent": null,
      "payment_method_options": {},
      "payment_method_types": [
        "card"
      ],
      "payment_status": "paid",
      "setup_intent": "seti_1J0d8eJvSJBZN02Kwwzupxxx",
      "shipping": null,
      "shipping_address_collection": null,
      "submit_type": null,
      "subscription": "sub_JduyaYhZ5UrRn1",
      "success_url": "http://3.129.28.xxx/subscriptions/success?session_id={CHECKOUT_SESSION_ID}",
      "total_details": {
        "amount_discount": 0,
        "amount_shipping": 0,
        "amount_tax": 0
      }
    }
  },
  "id": "evt_1J0d8gJvSJBZN02KkHPwAxxx",
  "livemode": false,
  "object": "event",
  "pending_webhooks": 3,
  "request": {
    "id": null,
    "idempotency_key": null
  },
  "type": "checkout.session.completed"
}

例:event取得後各種IDを取得

client_reference_id,customer,subscriptionの3つのデータが欲しい場合

1
2
3
4
5
6
session = event['data']['object']
 
# Fetch all the required data from session
client_reference_id = session.get('client_reference_id')
stripe_customer_id = session.get('customer')
stripe_subscription_id = session.get('subscription')

顧客データ詳細を取得

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
session = event['data']['object']
stripe_customer_id = session.get('customer')
retrieve = stripe.Customer.retrieve(stripe_customer_id)
 
#以下取得できるデータ一覧
{
"address": {
"city": null,
"country": "JP",
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"balance": 4,
"created": 1623314935,
"currency": "jpy",
"default_source": null,
"delinquent": false,
"description": null,
"discount": null,
"email": "xxxxxxxx@gmail.com",
"id": "cus_Je1cRQy1VsbQrb",
"invoice_prefix": "77146EAE",
"invoice_settings": {
"custom_fields": null,
"default_payment_method": null,
"footer": null
},
"livemode": false,
"metadata": {},
"name": "xxxxxx KAWAZOE",
"next_invoice_sequence": 2,
"object": "customer",
"phone": null,
"preferred_locales": [],
"shipping": null,
"tax_exempt": "none"
}

例:顧客データ詳細取得後各種情報を取得

1
2
3
4
5
6
#メールアドレスを取得したい場合
customer_email = retrieve['email']
 
#価格の取得
currency = retrieve['currency']
amount = retrieve['balance']

更に顧客データ詳細を表示

※但しview内にて取得する方法は不明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
stripe_customer = StripeCustomer.objects.get(user=request.user)
stripe.api_key = settings.STRIPE_SECRET_KEY
sub_id = stripe.Subscription.retrieve(stripe_customer.stripeSubscriptionId)
print(sub_id)
 
#以下取得できるデータ一覧
 
{
  "application_fee_percent": null,
  "billing_cycle_anchor": 1623372697,
  "billing_thresholds": null,
  "cancel_at": null,
  "cancel_at_period_end": false,
  "canceled_at": null,
  "collection_method": "charge_automatically",
  "created": 1623372697,
  "current_period_end": 1625964697,
  "current_period_start": 1623372697,
  "customer": "cus_JeH97oQYVT2Ehd",
  "days_until_due": null,
  "default_payment_method": "pm_1J0yaxJvSJBZN02Kb7nL7O37",
  "default_source": null,
  "default_tax_rates": [],
  "discount": null,
  "ended_at": null,
  "id": "sub_JeH9mHHGs3SrM2",
  "items": {
    "data": [
      {
        "billing_thresholds": null,
        "created": 1623372697,
        "id": "si_JeH9r5JrZtzGZS",
        "metadata": {},
        "object": "subscription_item",
        "plan": {
          "active": true,
          "aggregate_usage": null,
          "amount": 4,
          "amount_decimal": "4",
          "billing_scheme": "per_unit",
          "created": 1623289653,
          "currency": "jpy",
          "id": "price_1J0czZJvSJBZN02KVdyeJljf",
          "interval": "month",
          "interval_count": 1,
          "livemode": false,
          "metadata": {},
          "nickname": null,
          "object": "plan",
          "product": "prod_Jb1LklwtRAVkQB",
          "tiers_mode": null,
          "transform_usage": null,
          "trial_period_days": null,
          "usage_type": "licensed"
        },
        "price": {
          "active": true,
          "billing_scheme": "per_unit",
          "created": 1623289653,
          "currency": "jpy",
          "id": "price_1J0czZJvSJBZN02KVdyeJljf",
          "livemode": false,
          "lookup_key": null,
          "metadata": {},
          "nickname": null,
          "object": "price",
          "product": "prod_Jb1LklwtRAVkQB",
          "recurring": {
            "aggregate_usage": null,
            "interval": "month",
            "interval_count": 1,
            "trial_period_days": null,
            "usage_type": "licensed"
          },
          "tiers_mode": null,
          "transform_quantity": null,
          "type": "recurring",
          "unit_amount": 4,
          "unit_amount_decimal": "4"
        },
        "quantity": 1,
        "subscription": "sub_JeH9mHHGs3SrM2",
        "tax_rates": []
      }
    ],
    "has_more": false,
    "object": "list",
    "total_count": 1,
    "url": "/v1/subscription_items?subscription=sub_JeH9mHHGs3SrM2"
  },
  "latest_invoice": "in_1J0yazJvSJBZN02K4zKW5kTn",
  "livemode": false,
  "metadata": {},
  "next_pending_invoice_item_invoice": null,
  "object": "subscription",
  "pause_collection": null,
  "pending_invoice_item_interval": null,
  "pending_setup_intent": null,
  "pending_update": null,
  "plan": {
    "active": true,
    "aggregate_usage": null,
    "amount": 4,
    "amount_decimal": "4",
    "billing_scheme": "per_unit",
    "created": 1623289653,
    "currency": "jpy",
    "id": "price_1J0czZJvSJBZN02KVdyeJljf",
    "interval": "month",
    "interval_count": 1,
    "livemode": false,
    "metadata": {},
    "nickname": null,
    "object": "plan",
    "product": "prod_Jb1LklwtRAVkQB",
    "tiers_mode": null,
    "transform_usage": null,
    "trial_period_days": null,
    "usage_type": "licensed"
  },
  "quantity": 1,
  "schedule": null,
  "start_date": 1623372697,
  "status": "active",
  "transfer_data": null,
  "trial_end": null,
  "trial_start": null
}

HTMLにて上記データを表示

view.py

1
2
3
4
5
6
7
8
stripe_customer = StripeCustomer.objects.get(user=request.user)
stripe.api_key = settings.STRIPE_SECRET_KEY
subscription = stripe.Subscription.retrieve(stripe_customer.stripeSubscriptionId)
 
return render(request, 'home.html',{
    'subscription': subscription,
    'product': product,
    })

html

1
2
ProductDescription:{ product.description}
Price:{ subscription.plan.currency}} {{ subscription.plan.amount}}

 

 

ローカルでStripe CLI でwebhookをテスト

exeファイルをクリックしてもThis is a command line tool.
You need to open cmd.exe and run it from there.と出て消えてしまうので
exeファイルをShiftを押しながら右クリックする事で開く事ができる。

↓コツはカーソルをstripeから離れた白地の部分でShiftを押しながら
右クリックする事。
Stripeを選んだまま右クリックしてもPowershellウィンドウを開く事は
できない

windowsの場合ログインのコマンドは以下の通り。(stripe loginだけではだめ)

1
./stripe login

1
./stripe listen --forward-to localhost:8000/subscriptions/webhook/

このエントリーをはてなブックマークに追加

Tweet
[`yahoo` not found]
このエントリーを Google ブックマーク に追加
LinkedIn にシェア
LINEで送る


Filed Under: Django

Reader Interactions

コメントを残す コメントをキャンセル

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

Primary Sidebar

カテゴリー

  • AWS
  • Bootstrap
  • Dash
  • Django
  • flask
  • GIT(sourcetree)
  • Plotly/Dash
  • VPS
  • その他tool
  • ブログ
  • プログラミング
    • Bokeh
    • css
    • HoloViews
    • Jupyter
    • Numpy
    • Pandas
    • PosgreSQL
    • Python 基本
    • python3
      • webアプリ
    • python3解説
    • scikit-learn
    • scipy
    • vps
    • Wordpress
    • グラフ
    • コマンド
    • スクレイピング
    • チートシート
    • データクレンジング
    • ブロックチェーン
    • 作成実績
    • 時系列分析
    • 機械学習
      • 分析手法
      • 教師有り
    • 異常値検知
    • 自然言語処理
  • 一太郎
  • 数学
    • sympy
      • 対数関数(log)
      • 累乗根(n乗根)
    • 暗号学

Copyright © 2025 · Genesis Sample on Genesis Framework · WordPress · Log in