学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Django3.2 | クラウドソーシングアプリの構築 | 22 | Stripe

↓↓クリックして頂けると励みになります。


21 | 電話番号更新】 << 【ホーム】 >> 【23 | クレジットカード登録


まずは以下の手順でStripeのアカウントを取得してください。
mrradiology.hatenablog.jp


ダッシュボードで「公開可能キー」と「シークレットキー」をコピーします。

公開可能キーとシークレットキー
公開可能キーとシークレットキー


「crowdsource/settings.py」ファイルに記述を追加します。


記述追加 【Desktop/crowdsource/crowdsource/settings.py】164行目(末尾)

STRIPE_API_PUBLIC_KEY = "ご自分の公開可能キーを入れてください。"
STRIPE_API_SECRET_KEY = "ご自分のシークレットキーを入れてください。"



モデルを作成します。
「core/models.py」ファイルを以下のように編集します。


記述編集 【Desktop/crowdsource/core/models.py】

from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class Customer(models.Model):
  user = models.OneToOneField(User, on_delete=models.CASCADE)
  avatar = models.ImageField(upload_to='customer/avatars/', blank=True, null=True)
  phone_number = models.CharField(max_length=50, blank=True)
  stripe_customer_id = models.CharField(max_length=255, blank=True)
  stripe_payment_method_id = models.CharField(max_length=255, blank=True)
  stripe_card_last4 = models.CharField(max_length=255, blank=True)

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



マイグレーションファイルを作成します。
コマンド
python manage.py makemigrations


マイグレーションを適用します。
コマンド
python manage.py migrate


「crowdsource/urls.py」ファイルに記述を追加します。


記述追加 【Desktop/crowdsource/crowdsource/urls.py】15行目

from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views
from django.conf import settings
from django.conf.urls.static import static

from core import views

from core.customer import views as customer_views
from core.courier import views as courier_views

customer_urlpatters = [
    path('', customer_views.home, name="home"),
    path('profile/', customer_views.profile_page, name="profile"),
        path('payment_method/', customer_views.payment_method_page, name="payment_method"),
]

courier_urlpatters = [
    path('', courier_views.home, name="home"),
]


urlpatterns = [
    path('admin/', admin.site.urls),
    path('oauth/', include('social_django.urls', namespace='social')),
    path('', views.home),

    path('sign-in/', auth_views.LoginView.as_view(template_name="sign_in.html")),
    path('sign-out/', auth_views.LogoutView.as_view(next_page="/")),
    path('sign-up/', views.sign_up),

    path('customer/', include((customer_urlpatters, 'customer'))),
    path('courier/', include((courier_urlpatters, 'courier'))),

]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)



「core/customer/views.py」ファイルを編集します。


記述追加 【Desktop/crowdsource/core/customer/views.py】65行目

import firebase_admin

from firebase_admin import credentials, auth

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from core.customer import forms

from django.contrib import messages
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth import update_session_auth_hash
from django.conf import settings

cred = credentials.Certificate(settings.FIREBASE_ADMIN_CREDENTIAL)
firebase_admin.initialize_app(cred)

@login_required()
def home(request):
    return redirect(reverse('customer:profile'))

@login_required(login_url="/sign-in/?next=/customer/")
def profile_page(request):
    user_form = forms.BasicUserForm(instance=request.user)
    customer_form = forms.BasicCustomerForm(instance=request.user.customer)
    password_form = PasswordChangeForm(request.user)

    if request.method == "POST":
 
        if request.POST.get('action') == 'update_profile':
            user_form = forms.BasicUserForm(request.POST, instance=request.user)
            customer_form = forms.BasicCustomerForm(request.POST, request.FILES, instance=request.user.customer)

            if user_form.is_valid() and customer_form.is_valid():
                user_form.save()
                customer_form.save()

                messages.success(request, 'プロフィールが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_password':
            password_form = PasswordChangeForm(request.user, request.POST)
            if password_form.is_valid():
                user = password_form.save()
                update_session_auth_hash(request, user)

                messages.success(request, 'パスワードが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_phone':
            # Get Firebase user data
            firebase_user = auth.verify_id_token(request.POST.get('id_token'))

            request.user.customer.phone_number = firebase_user['phone_number']
            request.user.customer.save()
            messages.success(request, '電話番号が更新されました。')
            return redirect(reverse('customer:profile'))

    return render(request, 'customer/profile.html', {
        "user_form": user_form,
        "customer_form": customer_form,
        "password_form": password_form,
    })

@login_required(login_url="/sign-in/?next=/customer/")
def payment_method_page(request):
    return render(request, 'customer/payment_method.html')



「core/templates/customer」フォルダに「payment_method.html」ファイルを新規作成します。


新規作成 【Desktop/crowdsource/core/templates/customer/payment_method.html】

{% extends 'customer/base.html' %}
{% load bootstrap4 %}

{% block main %}

<b class="text-secondary">クレジットカード登録</b>

<div class="card bg-white mt-2 mb-5">
  <div class="card-body">


  </div>
</div>

{% endblock %}



ブラウザを確認します。
http://127.0.0.1:8000/customer/payment_method/

クレジットカード登録
クレジットカード登録



Stripeをインストールします。
コマンド
pip install stripe==2.55.1


バージョン確認します。
コマンド
pip freeze > requirements.txt


内容確認 【Desktop/crowdsource/requirements.txt】

asgiref==3.7.2
beautifulsoup4==4.12.2
CacheControl==0.13.1
cachetools==5.3.1
certifi==2023.7.22
cffi==1.15.1
charset-normalizer==3.2.0
cryptography==41.0.3
defusedxml==0.7.1
Django==3.2.20
django-bootstrap4==2.3.1
firebase-admin==4.4.0
google-api-core==1.34.0
google-api-python-client==2.97.0
google-auth==2.22.0
google-auth-httplib2==0.1.0
google-cloud-core==2.3.3
google-cloud-firestore==2.11.1
google-cloud-storage==2.10.0
google-crc32c==1.5.0
google-resumable-media==2.5.0
googleapis-common-protos==1.60.0
grpcio==1.57.0
grpcio-status==1.48.2
httplib2==0.22.0
idna==3.4
msgpack==1.0.5
oauthlib==3.2.2
Pillow==10.0.0
proto-plus==1.22.3
protobuf==3.20.3
pyasn1==0.5.0
pyasn1-modules==0.3.0
pycparser==2.21
PyJWT==2.8.0
pyparsing==3.1.1
python3-openid==3.2.0
pytz==2023.3
requests==2.31.0
requests-oauthlib==1.3.1
rsa==4.9
six==1.16.0
social-auth-app-django==4.0.0
social-auth-core==4.4.2
soupsieve==2.5
sqlparse==0.4.4
stripe==2.55.1
typing_extensions==4.7.1
uritemplate==4.1.1
urllib3==1.26.16



「core/customer/views.py」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/customer/views.py】

import firebase_admin
from firebase_admin import credentials, auth
import stripe

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from core.customer import forms

from django.contrib import messages
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth import update_session_auth_hash
from django.conf import settings

cred = credentials.Certificate(settings.FIREBASE_ADMIN_CREDENTIAL)
firebase_admin.initialize_app(cred)

stripe.api_key = settings.STRIPE_API_SECRET_KEY

@login_required()
def home(request):
    return redirect(reverse('customer:profile'))

@login_required(login_url="/sign-in/?next=/customer/")
def profile_page(request):
    user_form = forms.BasicUserForm(instance=request.user)
    customer_form = forms.BasicCustomerForm(instance=request.user.customer)
    password_form = PasswordChangeForm(request.user)

    if request.method == "POST":
 
        if request.POST.get('action') == 'update_profile':
            user_form = forms.BasicUserForm(request.POST, instance=request.user)
            customer_form = forms.BasicCustomerForm(request.POST, request.FILES, instance=request.user.customer)

            if user_form.is_valid() and customer_form.is_valid():
                user_form.save()
                customer_form.save()

                messages.success(request, 'プロフィールが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_password':
            password_form = PasswordChangeForm(request.user, request.POST)
            if password_form.is_valid():
                user = password_form.save()
                update_session_auth_hash(request, user)

                messages.success(request, 'パスワードが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_phone':
            # Get Firebase user data
            firebase_user = auth.verify_id_token(request.POST.get('id_token'))

            request.user.customer.phone_number = firebase_user['phone_number']
            request.user.customer.save()
            messages.success(request, '電話番号が更新されました。')
            return redirect(reverse('customer:profile'))

    return render(request, 'customer/profile.html', {
        "user_form": user_form,
        "customer_form": customer_form,
        "password_form": password_form,
    })

@login_required(login_url="/sign-in/?next=/customer/")
def payment_method_page(request):
    current_customer = request.user.customer

    # Save stripe customer infor
    if not current_customer.stripe_customer_id:
        customer = stripe.Customer.create()
        current_customer.stripe_customer_id = customer['id']
        current_customer.save()    

    intent = stripe.SetupIntent.create(
        customer = current_customer.stripe_customer_id
    )

    return render(request, 'customer/payment_method.html', {
        "client_secret": intent.client_secret,
        "STRIPE_API_PUBLIC_KEY": settings.STRIPE_API_PUBLIC_KEY,
    })



「core/templates/customer/payment_method.html」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/templates/customer/payment_method.html】

{% extends 'customer/base.html' %}
{% load bootstrap4 %}

{% block head %}
<script src="https://js.stripe.com/v3/"></script>

<style>
    .StripeElement {
      height: 40px;
      padding: 10px 12px;
      width: 100%;
      color: #32325d;
      background-color: white;
      /* border: 1px solid transparent; */
      border: 1px solid #ced4da;
      border-radius: 4px;
  
      /* box-shadow: 0 1px 3px 0 #e6ebf1;
      -webkit-transition: box-shadow 150ms ease;
      transition: box-shadow 150ms ease; */
    }
  
    .StripeElement--focus {
      border-color: #80bdff;
      box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, .25);
    }
  
    .StripeElement--invalid {
      border-color: #fa755a;
    }
  
    .StripeElement--webkit-autofill {
      background-color: #fefde5 !important;
    }
  </style>
{% endblock %}

{% block main %}

<b class="text-secondary">クレジットカード登録</b>

<div class="card bg-white mt-2 mb-5">
  <div class="card-body">

    {% if request.user.customer.stripe_payment_method_id %}
    <div id="change-card" class="input-group">
      <input type="text" class="form-control" disabled
        value="**** **** **** {{ request.user.customer.stripe_card_last4 }}">
      <div class="input-group-append">
        <form method="POST">
          {% csrf_token %}
          <button type="submit" class="btn btn-danger">Remove</button>
        </form>
      </div>
    </div>

    {% else %}
    <form id="setup-form" data-secret="{{ client_secret }}">
      <div id="card-element"></div>
      <button id="card-button" class="btn btn-danger mt-3" type="button">
        カード登録
      </button>
    </form>
    {% endif %}


  </div>
</div>

<script>

    var stripe = Stripe("{{ STRIPE_API_PUBLIC_KEY }}");

    var elements = stripe.elements();
    var cardElement = elements.create('card');
    cardElement.mount('#card-element');

</script>

{% endblock %}



ブラウザを確認します。
クレジットカード登録フォームが完成しました。
まだ登録はできませんが、テストカードは「4242 4242 4242 4242」を使用してください。
http://127.0.0.1:8000/customer/payment_method/

クレジットカード登録フォーム
クレジットカード登録フォーム



↓↓クリックして頂けると励みになります。


21 | 電話番号更新】 << 【ホーム】 >> 【23 | クレジットカード登録