【问题标题】:Saving data after non-Django Form submission非 Django 表单提交后保存数据
【发布时间】:2021-07-15 19:06:28
【问题描述】:

我有一张由各种元素组成的付款表格。

我的问题是,新的条纹用户的卡直到提交表单后才注册。

我知道如果我的表单有一个新添加的地址,我可以使用 form.is_valid() 但如果我的地址是已经保存的地址,则不适用。但是有没有一种方法可以在表单提交后使用stripe.PaymentMethod.list 设置卡片,而不管 Django 表单是否是其中的一部分?

表格

<form method="POST" id="subscription-form" data-secret="{{client_secret}}">
            {% csrf_token %}
            <label class="block uppercase text-gray-600 text-xs font-bold mb-2">Payment Details</label>
            {% if payment_methods %}
            
            <div class="form-check my-3 bg-gray-200 p-2 rounded-md">
                <input class="form-check-input" type="radio" name="payment-methods" id="add-new-card"
                    value="add-new-card" onclick="addCard()" {%if payment_methods %} {%else%}checked="checked" {%endif%}
                    required>
                <label class="form-check-label" for="add-new-card">
                    Add new payment method
                </label>

                <div id="new-card" style="display: none;">
                    <label class="block uppercase text-gray-600 text-xs mb-2" for="cardholder-name">
                        Name on Card
                    </label>
                    <input id="cardholder-name"
                        class="mb-2 border-0 px-3 py-3 placeholder-gray-300 text-gray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
                        value="{{customer.name}}" detype="text">
                    <!-- placeholder for Elements -->
                    <label class="block uppercase text-gray-600 text-xs  mb-2" for="card-element">
                        Card Details
                    </label>
                    <div id="card-element"
                        class="mb-2 border-0 px-3 py-3 placeholder-gray-300 text-gray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150">
                        <!-- A Stripe Element will be inserted here. -->
                    </div>
                    <div id="card-result"></div>
                    <div id="card-errors" class="my-2" role="alert"></div>

                </div>
            </div>
            {% if saved_customer %}
            {% for method in payment_methods %}

            <div class="form-check my-3 bg-gray-200 p-2 rounded-md">
                <input class="form-check-input" type="radio" name="payment-methods" id="{{method.card}}"
                    value="{{method.id}}" onclick="hideCard()" {% if forloop.first %} checked="checked" {%endif%}>
                <label class="form-check-label" for="{{method.card}}">
                    {{method.card.brand}} ending in {{method.card.last4}}
                </label>
            </div>
            {% endfor %}

            {% endif %}
            {% else %}
            <div class="form-check my-3 bg-gray-200 p-2 rounded-md">
                <input class="form-check-input" type="radio" name="payment-methods" id="add-new-card"
                    value="add-new-card" checked="checked"
                    required>
                <label class="form-check-label" for="add-new-card">
                    Add new payment method
                </label>

                <div id="new-card">
                    <label class="block uppercase text-gray-600 text-xs mb-2" for="cardholder-name">
                        Name on Card
                    </label>
                    <input id="cardholder-name"
                        class="mb-2 border-0 px-3 py-3 placeholder-gray-300 text-gray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
                        value="{{customer.name}}" detype="text">
                    <!-- placeholder for Elements -->
                    <label class="block uppercase text-gray-600 text-xs  mb-2" for="card-element">
                        Card Details
                    </label>
                    <div id="card-element"
                        class="mb-2 border-0 px-3 py-3 placeholder-gray-300 text-gray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150">
                        <!-- A Stripe Element will be inserted here. -->
                    </div>
                    <div id="card-result"></div>
                    <div id="card-errors" class="my-2" role="alert"></div>

                </div>
            </div>
            {% endif %}


            <label class="block uppercase text-gray-600 text-xs font-bold mb-2">Address</label>
            <div id="address-list">
                <div class="form-check my-3 bg-gray-200 p-2 rounded-md">
                    <input class="form-check-input" type="radio" name="addresses" id="new-address" value="new-address"
                        onclick="showAddress()" {%if addresses%} {%else%}checked="checked" {%endif%}>

                    <label class="form-check-label" for="new-address">
                        New Address
                    </label>
                    <span id="address-form"></span>
                </div>

                {% for address in addresses %}
                <div class="form-check my-3 bg-gray-200 p-2 rounded-md">
                    <input class="form-check-input" type="radio" name="addresses" id="{{address.id}}"
                        value="{{address.id}}" onclick="hideAddress()" {% if forloop.first %} checked="checked"
                        {%endif%} required>
                    <label class="form-check-label" for="{{address.id}}">
                        {{address.name}} - {{address.line_1}}
                    </label>
                </div>
                {% endfor %}
            </div>

            <input type="hidden" id="email" name='email' value='{{customer.email}}'>



            <div>
                <p class="text-xs">By confirming, you agree that you will be charged immediately, and then monthly for
                    this product until cancelled</p>
                <button id="submit" type="submit"
                    class="w-full mt-2 bg-blue-300 text-blue-900 font-medium rounded p-3">Confirm
                    and Pay</button>
            </div>

        </form>

查看

@login_required
def subscription_new(request, product):
    stripe.api_key = STRIPE_SECRET_KEY
    title = "New Subscription for " + product
    product = Product.objects.get(slug=product)
    customer = Customer.objects.get(user=request.user.id)
    addresses = Address.objects.filter(customer=customer)
    current_day = datetime.date.today().day
    
    # maintain order day in short months
    if current_day > 28:
        current_day = 1
    stripe_amount = str(int(round(product.price, 2) * 100))
    context = {
        'title' : title,
        'product' : product,
        'customer' : customer,
        'addresses' : addresses,
        'current_day' : current_day,
        'STRIPE_PUBLIC_KEY' : STRIPE_PUBLIC_KEY,
    }
    card = request.POST.get('payment-methods')
    if customer.stripe_id:
        payment_methods = stripe.PaymentMethod.list(
                customer=customer.stripe_id,
                type="card",
            )
        context['saved_customer'] = True
        context['payment_methods'] = payment_methods
    else:
        print('no  stripe id ')
        new_customer = stripe.Customer.create(name=customer.name, email=customer.email)    
        customer.stripe_id = new_customer.id
        customer.save()
        context['saved_customer'] = False
    intent = stripe.SetupIntent.create(customer=customer.stripe_id)
    client_secret = intent.client_secret
    context['client_secret'] = client_secret

    if request.method == 'POST':
        print("method is post")
        address = request.POST.get('addresses')
        if address == 'new-address':
            form = AddressForm(request.POST)
            address = form.save(commit=False)
            address.customer = customer
            address.save()
        else:
            address = Address.objects.get(id=address)

        if customer.stripe_id:
            payment_methods = stripe.PaymentMethod.list(
                customer=customer.stripe_id,
                type="card",
            )
            print("customer has id")
            if card == "add-new-card":
                payment_methods = stripe.PaymentMethod.list(
                customer=customer.stripe_id,
                type="card",
            )
                new_card = payment_methods.data[0]
                # context['client_secret'] = client_secret
                subscription = Subscription.objects.create(customer=customer, product=product, address=address, renewal_day=current_day, payment_method=new_card.id)
                msg = 'Subscription created'
            else:
                subscription = Subscription.objects.create(customer=customer, product=product, address=address, renewal_day=current_day, payment_method=card)
                msg = 'Subscription created'
            messages.success(request, msg)
    # If method is not post
    else:
        form = AddressForm()
        context['form'] = form
   
    return render(request, 'accounts/subscription_new.html', context)

【问题讨论】:

    标签: django django-views django-forms


    【解决方案1】:

    假设AddressForm 是ModelForm,您也可以在模型的现有实例上使用它:

    address = Address.objects.get(id=address_id)
    form = AddressForm(request.POST, instance=address)
    

    此外,您还可以在保存表单之前执行其他操作。如果您希望注册条带支付方式以保存表单,请先注册,然后保存表单。

    如果要自定义AddressForm存储在地址上的数据,只需重写save方法,修改self.instance,再调用super().save()即可。

    或者,只需在表单上下文之外编辑 Address 对象。在表单save 方法中没有任何需要更新数据库的事情

    【讨论】:

    • 我不确定如何首先注册付款方式,因为stripe只有在表单提交后才有这些数据,我无法将表单分成多个提交。
    • 我还看到实例上的文档可用,我已将其用于编辑视图之类的事情,但不知道如何翻译以适应这种情况。我现在有它,我可以将字段更改为新地址或保存的地址,并且该决定是使用 JavaScript 做出的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 2012-07-16
    • 2015-07-01
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多