Я пытаюсь оплатить подписку на Stripe API в тестовом режиме, и моя плата продолжает снижаться. Кажется, все работает нормально, за исключением того, что я не могу получить "stripeToken" через POST. Я проверил это, напечатав различные переменные, которые мне нужны, и все они работают нормально ... но когда дело доходит до печати stripeToken, я получаю эту ошибку:
MultiValueDictKeyError at /memberships/payment/
'stripeToken'
Request Method: POST
Request URL: http://127.0.0.1:8000/memberships/payment/
Django Version: 2.2
Exception Type: MultiValueDictKeyError
Exception Value:
'stripeToken'
Exception Location: /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/utils/datastructures.py in __getitem__, line 80
Python Executable: /Library/Frameworks/Python.framework/Versions/3.8/bin/python3
Python Version: 3.8.2
Python Path:
['/Users/fred/Documents/yonder/videoservice',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python38.zip',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/lib-dynload',
'/Users/fred/Library/Python/3.8/lib/python/site-packages',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages']
Server time: Wed, 1 Apr 2020 16:20:53 -0700
Вот мой код представления:
def PaymentView(request):
user_membership = get_user_membership(request)
try:
selected_membership = get_selected_membership(request)
except:
return redirect(reverse("memberships:select"))
publishKey = settings.STRIPE_PUBLISHABLE_KEY
if request.method == "POST":
token = request.POST['stripeToken']
try:
token = request.POST['stripeToken']
customer = stripe.Customer.retrieve(user_membership.stripe_customer_id)
customer.source = token # 4242424242424242
customer.save()
subscription = stripe.Subscription.create(
customer=user_membership.stripe_customer_id,
items=[
{ "plan": selected_membership.stripe_plan_id },
]
)
return redirect(reverse('memberships:update-transactions',
kwargs={
'subscription_id': subscription.id
}))
except:
messages.info(request, "An error has occurred, investigate it in the console")
context = {
'publishKey': publishKey,
'selected_membership': selected_membership
}
return render(request, "memberships/membership_payment.html", context)
А вот мой HTML код
{% extends 'courses/base.html' %}
{% load static %}
{% block content %}
<link rel="stylesheet" type="text/css" href="{% static 'css/checkout.css' %}">
<div class="container">
<div class="row">
<h1>Payment</h1>
<div class="col-sm-4 col-md-4">
<p>Selected Membership: {{ selected_membership }}</p>
<p>Price: ${{ selected_membership.price }}<small>/mo.</small></p>
<button onclick="toggleDisplay();" class="btn btn-warning" style="width: 100%;">Checkout with a credit card</button>
<div id="collapseStripe" class="wrapper">
<script src="https://js.stripe.com/v3/"></script>
<form action="." method="post" id="payment-form">
{% csrf_token %}
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element" class="StripeElement StripeElement--empty"><div class="__PrivateStripeElement" style="margin: 0px !important; padding: 0px !important; border: none !important; display: block !important; background: transparent !important; position: relative !important; opacity: 1 !important;"><iframe frameborder="0" allowtransparency="true" scrolling="no" name="__privateStripeFrame3" allowpaymentrequest="true" src="https://js.stripe.com/v3/elements-inner-card-8a434729e4eb82355db4882974049278.html#style[base][color]=%2332325d&style[base][lineHeight]=18px&style[base][fontFamily]=%22Helvetica+Neue%22%2C+Helvetica%2C+sans-serif&style[base][fontSmoothing]=antialiased&style[base][fontSize]=16px&style[base][::placeholder][color]=%23aab7c4&style[invalid][color]=%23fa755a&style[invalid][iconColor]=%23fa755a&componentName=card&wait=false&rtl=false&features[noop]=false&origin=https%3A%2F%2Fstripe.com&referrer=https%3A%2F%2Fstripe.com%2Fdocs%2Fstripe-js%2Felements%2Fquickstart&controllerId=__privateStripeController0" title="Secure payment input frame" style="border: none !important; margin: 0px !important; padding: 0px !important; width: 1px !important; min-width: 100% !important; overflow: hidden !important; display: block !important; height: 18px;"></iframe><input class="__PrivateStripeElement-input" aria-hidden="true" style="border: none !important; display: block !important; position: absolute !important; height: 1px !important; top: 0px !important; left: 0px !important; padding: 0px !important; margin: 0px !important; width: 100% !important; opacity: 0 !important; background: transparent !important; pointer-events: none !important; font-size: 16px !important;"><input class="__PrivateStripeElement-safariInput" aria-hidden="true" tabindex="-1" style="border: none !important; display: block !important; position: absolute !important; height: 1px !important; top: 0px !important; left: 0px !important; padding: 0px !important; margin: 0px !important; width: 100% !important; opacity: 0 !important; background: transparent !important; pointer-events: none !important; font-size: 16px !important;"></div></div>
<!-- Used to display form errors. -->
<div id="card-errors" role="alert"></div>
</div>
<button>Submit Payment</button>
</form>
</div>
</div>
<div id="stripe-token-handler" class="is-hidden">Success! Got token: <span class="token"></span></div>
</div>
</div>
</div>
<!-- script for the stripe form -->
<script src="{% static 'js/checkout.js' %}"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<!-- script for toggling display of the form -->
<script type="text/javascript">
function toggleDisplay() {
var x = document.getElementById("collapseStripe");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
};
</script>
{% endblock content %}
А вот и заказ. js
// Create a Stripe client.
var stripe = Stripe('123456'); //key goes here
// Create an instance of Elements.
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
lineHeight: '18px',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
// Handle real-time validation errors from the card Element.
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
var successElement = document.getElementById('stripe-token-handler');
document.querySelector('.wrapper').addEventListener('click', function() {
successElement.className = 'is-hidden';
});
function stripeTokenHandler(token) {
successElement.className = '';
successElement.querySelector('.token').textContent = token.id;
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
Мои открытые / секретные ключи API находятся в моем файле настроек и я дважды проверил их; они оба правильные.
Что я здесь не так делаю? Это мой первый проект Django / Python. Ценю некоторое понимание. Спасибо.