【问题标题】:Django POST request Ajax cannot get data on server-sideDjango POST 请求 Ajax 无法在服务器端获取数据
【发布时间】:2020-09-26 01:59:07
【问题描述】:

我正在尝试在我的网站上使用订阅表单。我正在使用条纹。我可以使用他们的 API 将数据发送到 Stripe。但是,从 Stripe 接收数据后,我无法将数据保存在服务器端:

// In subscription.js:

$( function() {
    var customerEmail          = document.querySelector("[data-email]").getAttribute('data-email');
    var submissionURL          = document.querySelector("[data-redirect]").getAttribute('data-redirect');
    var stripeSubscriptionForm = document.getElementById('subscriptionId');
    var cardElement = elements.create("card", { style: style });

    // Mounting the card element in the template
    cardElement.mount("#card-element");

    stripeSubscriptionForm.addEventListener('submit', function(event){
        event.preventDefault();  // Before submitting, we need to send the data to our database too
        theForm        = event.target;  // getting the form; same as using getElementById, but using the event only
        theFormData    =  new FormData(theForm);

    stripe.createPaymentMethod( {   type            : 'card',                // this is what's sent to stripe
                                    card            : cardElement,
                                    billing_details : { email : customerEmail, }
                                },

                                )

                                .then( (result) => {                       // Once stripe returns the result
                                       // Building the data
                                       theFormData.append('card', cardElement);    
                                       theFormData.append('billing_details', customerEmail);
                                       theFormData.append('payement_method', result.paymentMethod.id);

                                       // Setting up the request
                                       const xhr = new XMLHttpRequest()    // Creating an XHR request object
                                       xhr.open(method, url);              // Creating a GET request

                                       // Setting up the header

                                       xhr.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest");  // Ajax header
                                       xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); // Ajax header
                                       xhr.setRequestHeader("X-CSRF-TOKEN", "{{ csrf_token }}");  // csrf_token

                                       xhr.onload = function() {           // After server sends response data back
                                           console.log('Got something back from server ')
                                           const response = xhr.response;  // 1) get the response object of the XHR request object

                                           if (xhr.status === 201 ){       // If the item is created
                                               const responseJson = JSON.parse(response)
                                               console.log('and json response: ', responseJson);  
                                           }
                                           else{
                                               console.log('httpRequest status: ', httpRequest.status);  // Let's see what's going on
                                           }
                                       }
                                       // Sending the form data
                                       xhr.send(theFormData);                         // Sending the xhr request


                                    });
});

那么,在我的views.py中:

def post(self, request, *args, **kwargs):
        ''' Receives the subscription form '''            
        subscriber_form       = SubscriberForm(request.POST)
        billing_address_form  = CompanyAddressForm(request.POST)
        subscription_form     = SubscriptionForm(request.POST)

        if subscriber_form.is_valid() and billing_address_form.is_valid() and subscription_form.is_valid():
            print ('forms are valid')
            billing_address               = billing_address_form.save()
            subscriber_instance           = subscriber_form.save(commit = False)
            subscriber_instance.address   = billing_address
            print ('######################################################')

            if request.META.get('CONTENT_TYPE', '').lower() == 'application/json' and len(request.body) > 0:
                print ('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
                try:
                    body_data = json.loads(request.body)
                    print (body_data)

                except Exception as e:
                    request_body = request.body

                    print (request_body)print ('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
            else:
                print ("request.META.get('CONTENT_TYPE', ''): ", request.META.get('CONTENT_TYPE', '') )

            ## Creating a customer in stripe: Need the data from the front-end:
            customer_stripe = stripe.Customer.create( payment_method   =  data.get('payment_method', None),
                                                      email            =  data.get('email', None),
                                                      invoice_settings =  { 'default_payment_method': data.get('payment_method', None), },
                                                    )

            ## Creating a subscription in stripe
            subscription = stripe.Subscription.create( customer = customer_stripe.id, items = [{'plan': plan_idx, }],  # plan_idx is the plan id from stripe
                                                       expand   = ['latest_invoice.payment_intent'] )

            form = SubscriptionForm(request.POST)            

            if form.is_valid():                
                subscription_instance = form.save()

            else:
                context['form']    = SubscriptionForm(request.POST)

                return render(request, self.template_name, context)


            ## Creating the same customer for ourselves
            user              = request.user 
            ...

            customer, created = Customer.objects.get_or_create(...)

            return render(request, reverse('dashboard') )
        else:
            ... # Re-render the forms with errors

            return render(request, self.template_name, context)

问题是我明白了:

######################################################
request.META.get('CONTENT_TYPE', ''):  multipart/form-data; boundary=----WebKitFormBoundaryIeaE9GpJ2EXQBkZK

如何访问我的数据?我的表单都没有图像或文件,但即使我的表单是多部分/表单数据,我将来可能需要向订阅者添加头像,我如何使用body_data = json.loads(request.body) 获取数据?

编辑 1: 所以,我想既然我已经访问了请求对象以在 post 方法中获取我的表单,我可能应该首先准备 request.body,因为 Django 抱怨一旦你触摸请求对象,你就无法再次读取流。所以,这里是修改:

 def post(self, request, *args, **kwargs):
    ''' Receives the subscription form '''
    request_body = request.body
    try:
        body_data = json.loads(request_body)

    except Exception as e:
        print ('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
        print (request_body)
        print ('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')

但这会返回

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
request_body:  b'------WebKitFormBoundaryBBzJCNQS96b76EKx\r\nContent-Disposition: form-data; name="csrfmiddlewaretoken"\r\n\r\n0ryuWTIxVRPjDGe0c9Fxj7Sc3KeCmBtAkiFK5EAlriY0QtAmwo6ip\r\n------WebKitFormBoundaryBBzJCNQS96b76EKx\r\nContent-Disposition: form-data; name="name"\r\n\r\nABC\r\n------WebKitFormBoundaryBBzJCNQS96b76EKx\r\nContent-Disposition: form-data; name="email"\r\n\r\nemail@gmail.com\r\n...'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

问题是为什么会引发异常,这个 WebKitFormBoundary 业务是什么?

编辑 2 因此,当我在服务器端打印 POST 请求时,我确实得到了数据:

def post(self, request, *args, **kwargs):
    ''' Receives the subscription form '''
    # request_body = request.body     
    print ('request_post: ', request.POST)
    print ('')

在我的控制台中返回以下内容:

request_post:  <QueryDict: {'csrfmiddlewaretoken': ['OOPVcfGU2WfcPl3ld-Jx1L7XI1vSHfFhp0v1SIzQHpIyWrrhrH0d03HYnS7DdssZ'], 'name': ['ABC'], 'email': ['email@gmail.com'],...

但是,当我发布 request.body 时,我得到:

request_body:  b'------WebKitFormBoundaryG87zmkiNu0fTWY0g\r\nContent-Disposition: form-data; name="csrfmiddlewaretoken"\r\n\r\nOOPVcfGU2WfcPl3ld-Jx1L7XI1vSHfFhp0v1SIzQHpIyWrrhrH0d03HYnS7DdssZ\r\n------WebKitFormBoundaryG87zmkiNu0fTWY0g\r\nContent-Disposition: form-data; name="name"\r\n\r\nABC\r\n------WebKitFormBoundaryG87zmkiNu0fTWY0g\r\nContent-Disposition: form-data; name="email"\r\n\r\nemail@gmail.com\r\n------WebKitFormBoundaryG87zmkiNu0fTWY0g\r\n...'

那么,这是否告诉我们数据正在进入服务器端,并且在检索数据时出现问题?

【问题讨论】:

  • 你为什么用GET方法发送你的数据并试图在你的视图中得到它的body
  • 你怎么说我用了GET?我确实看过,我正在使用 POST 请求
  • 它在您的 javascript 代码中显示为xhr.open(method, url); // Creating a GET request。当您想要访问已发布给您的数据时。您可以通过variable = request.POST["name_of_data_field"] 或更好的版本variable = request.POST.get("name_of_data_field", None) 而不是request.body 进行操作
  • @Mahyar,我应该在我的 Django 视图中使用 .POST 是正确的。我发现了为什么我应该使用 .POST 而不是 .body。一般来说,你会使用 .body 来处理 JSON,正如这个答案 https://stackoverflow.com/a/37570142/3549766 所建议的那样,如果你能详细说明为什么在这种特殊情况下应该使用 .POST 方法,那么我建议你创建一个答案,我会将其标记为正确答案。这是因为本例中的原因可以帮助其他人处理 Ajax、JSON、formData。

标签: django ajax


【解决方案1】:

我认为您的问题在于您在 javascript 代码中发布的数据, 你不是发送一个 json 对象到你的服务器,而是一个表单对象 theFormData = new FormData(theForm);

如果你想发布一个 json 对象,你应该首先创建一个 javascript 对象,然后在其上使用JSON.stringyfy 方法来创建一个 json 并将该 json 发送到你的服务器

例如

sendData = {field1: "value1", field2: "value2"}

xhr.send(JSON.stringify(sendData));

【讨论】:

    猜你喜欢
    • 2017-05-21
    • 2018-01-13
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 1970-01-01
    • 2023-03-30
    • 2013-05-20
    相关资源
    最近更新 更多