在通过 Stripe Checkout Session 收到付款后,如何在 Django 中更改对我的 'Order' 进行更改?
How to change make changes to my 'Order' in Django after receiving payment by Stripe Checkout Session?
我正在用 Django 制作一个电子商务网站,想使用 Stripe Checkout Session 来接收在线支付。
我按照 https://stripe.com/docs/api/checkout/sessions for creating checkout sessions and https://stripe.com/docs/webhooks/build 创建了 webhook。
我可以顺利收到付款,但我想在收到付款后立即将 'order' 更改为 'complete = True'。但是视图'stripe_webhook'的请求没有user属性,所以我无法调用'request.user'获取对应的'order'。我该如何解决这个问题?非常感谢。
models.py
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True, null = True, blank = True)
date_completed = models.DateTimeField(null = True, blank = True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
def __str__(self):
return f'{self.user.username} {self.date_created}'
views.py
@login_required
def stripe_payment(request):
return render(request, 'stripe_payment.html', {})
@csrf_exempt
def stripe_config(request):
if request.method == 'GET':
stripe_config = {'publicKey': settings.STRIPE_PUBLISHABLE_KEY}
return JsonResponse(stripe_config, safe=False)
@csrf_exempt
def stripe_create_checkout_session(request):
if request.method == 'GET':
domain_url = 'http://localhost:8000/'
stripe.api_key = settings.STRIPE_SECRET_KEY
order = Order.objects.get(user = request.user, complete = False)
total = int(order.get_cart_items_total) * 100
try:
checkout_session = stripe.checkout.Session.create(
success_url = domain_url + 'success?session_id={CHECKOUT_SESSION_ID}',
cancel_url = domain_url + 'cancelled/',
payment_method_types = ['card'],
mode = 'payment',
line_items = [
{
'name': ' ',
'quantity': 1,
'currency': 'usd',
'amount': total,
}
]
)
return JsonResponse({'sessionId': checkout_session['id']})
except Exception as e:
return JsonResponse({'error': str(e)})
@csrf_exempt
def stripe_webhook(request):
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
)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
# Handle the checkout.session.completed event
if event['type'] == 'checkout.session.completed':
print("Payment was successful.")
#request of this view does not have any user attribute
order = Order.objects.get(user = request.user, complete = False)
transaction_id = datetime.now().timestamp()
order.complete = True
order.transaction_id = transaction_id
order.date_completed = datetime.now()
order.save()
print("Order was successfully updated and saved.")
return HttpResponse(status=200)
def payment_success(request):
return render(request, 'success.html', {})
def payment_cancel(request):
return render(request, 'cancelled.html', {})
stripe.js
fetch("/stripe_config/")
.then((result) => { return result.json(); })
.then((data) => {
// Initialize Stripe.js
const stripe = Stripe(data.publicKey);
// Event handler
document.querySelector("#submitBtn").addEventListener("click", () => {
// Get Checkout Session ID
fetch("/stripe_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);
});
});
});
urls.py
来自 django.urls 导入路径
从 .views 导入 *
urlpatterns = [
path('stripe_payment/', stripe_payment, name = 'stripe_payment'),
path('stripe_config/', stripe_config, name = 'stripe_config'),
path('stripe_create_checkout_session/', stripe_create_checkout_session, name = 'stripe_create_checkout_session'),
path('webhook/', stripe_webhook),
path('success/', payment_success, name = 'payment_success'),
path('cancelled/', payment_cancel, name = 'payment_cancel'),
]
stripe_payment.html
{% extends 'base.html' %}
{% load static %}
{% block head_title %}Django + Stripe Checkout{% endblock %}
{% block extra_head %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.2/css/bulma.min.css">
<script src="https://js.stripe.com/v3/"></script>
<script src="{% static 'js/stripe.js' %}"></script>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
{% endblock %}
{% block content %}
<!--Main layout-->
<main>
<section class="section">
<div class="container">
<button class="button is-primary" id="submitBtn">Purchase!</button>
</div>
</section>
</main>
<!--Main layout-->
{% endblock content %}
Stripe webhook 事件有一个 data.object
属性 代表事件相关的对象。
在 checkout.session.completed
事件的情况下,data.object
将描述一个 Checkout Session 对象,其中包含对创建的 customer ID 的引用。
webhook 事件不会有 request.user
属性 因为调用来自 Stripe 而不是来自您的客户端。您可能想要收集 Stripe 客户 ID 或结帐会话 ID,并将其映射到您自己的数据库中的用户。
我正在用 Django 制作一个电子商务网站,想使用 Stripe Checkout Session 来接收在线支付。
我按照 https://stripe.com/docs/api/checkout/sessions for creating checkout sessions and https://stripe.com/docs/webhooks/build 创建了 webhook。
我可以顺利收到付款,但我想在收到付款后立即将 'order' 更改为 'complete = True'。但是视图'stripe_webhook'的请求没有user属性,所以我无法调用'request.user'获取对应的'order'。我该如何解决这个问题?非常感谢。
models.py
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True, null = True, blank = True)
date_completed = models.DateTimeField(null = True, blank = True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
def __str__(self):
return f'{self.user.username} {self.date_created}'
views.py
@login_required
def stripe_payment(request):
return render(request, 'stripe_payment.html', {})
@csrf_exempt
def stripe_config(request):
if request.method == 'GET':
stripe_config = {'publicKey': settings.STRIPE_PUBLISHABLE_KEY}
return JsonResponse(stripe_config, safe=False)
@csrf_exempt
def stripe_create_checkout_session(request):
if request.method == 'GET':
domain_url = 'http://localhost:8000/'
stripe.api_key = settings.STRIPE_SECRET_KEY
order = Order.objects.get(user = request.user, complete = False)
total = int(order.get_cart_items_total) * 100
try:
checkout_session = stripe.checkout.Session.create(
success_url = domain_url + 'success?session_id={CHECKOUT_SESSION_ID}',
cancel_url = domain_url + 'cancelled/',
payment_method_types = ['card'],
mode = 'payment',
line_items = [
{
'name': ' ',
'quantity': 1,
'currency': 'usd',
'amount': total,
}
]
)
return JsonResponse({'sessionId': checkout_session['id']})
except Exception as e:
return JsonResponse({'error': str(e)})
@csrf_exempt
def stripe_webhook(request):
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
)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
# Handle the checkout.session.completed event
if event['type'] == 'checkout.session.completed':
print("Payment was successful.")
#request of this view does not have any user attribute
order = Order.objects.get(user = request.user, complete = False)
transaction_id = datetime.now().timestamp()
order.complete = True
order.transaction_id = transaction_id
order.date_completed = datetime.now()
order.save()
print("Order was successfully updated and saved.")
return HttpResponse(status=200)
def payment_success(request):
return render(request, 'success.html', {})
def payment_cancel(request):
return render(request, 'cancelled.html', {})
stripe.js
fetch("/stripe_config/")
.then((result) => { return result.json(); })
.then((data) => {
// Initialize Stripe.js
const stripe = Stripe(data.publicKey);
// Event handler
document.querySelector("#submitBtn").addEventListener("click", () => {
// Get Checkout Session ID
fetch("/stripe_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);
});
});
});
urls.py 来自 django.urls 导入路径 从 .views 导入 *
urlpatterns = [
path('stripe_payment/', stripe_payment, name = 'stripe_payment'),
path('stripe_config/', stripe_config, name = 'stripe_config'),
path('stripe_create_checkout_session/', stripe_create_checkout_session, name = 'stripe_create_checkout_session'),
path('webhook/', stripe_webhook),
path('success/', payment_success, name = 'payment_success'),
path('cancelled/', payment_cancel, name = 'payment_cancel'),
]
stripe_payment.html
{% extends 'base.html' %}
{% load static %}
{% block head_title %}Django + Stripe Checkout{% endblock %}
{% block extra_head %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.2/css/bulma.min.css">
<script src="https://js.stripe.com/v3/"></script>
<script src="{% static 'js/stripe.js' %}"></script>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
{% endblock %}
{% block content %}
<!--Main layout-->
<main>
<section class="section">
<div class="container">
<button class="button is-primary" id="submitBtn">Purchase!</button>
</div>
</section>
</main>
<!--Main layout-->
{% endblock content %}
Stripe webhook 事件有一个 data.object
属性 代表事件相关的对象。
在 checkout.session.completed
事件的情况下,data.object
将描述一个 Checkout Session 对象,其中包含对创建的 customer ID 的引用。
webhook 事件不会有 request.user
属性 因为调用来自 Stripe 而不是来自您的客户端。您可能想要收集 Stripe 客户 ID 或结帐会话 ID,并将其映射到您自己的数据库中的用户。