EarlyCoder
EarlyCoder

Reputation: 1313

Django POST request Ajax cannot get data on server-side

I am trying to get a subscription form working on my site. I am using Stripe. I can send data to Stripe using their API. However, I'm not able to save the data on the server-side after receiving it from 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


                                    });
});

Then, in my 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)

The problem is I get:

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

How do I access my data? None of my forms have image or files, but for even if my form is multipart/form-data, which I may need to in future to add headshot to the subscriber, how can I get the data using body_data = json.loads(request.body)?

Edit 1: So, I figured since I have accessed the request object to get my forms in the post method, may be I should first ready the request.body since Django is complaining that once you touch the request object, you cannot read the stream again. So, here is the modification:

 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 ('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')

but this returns

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
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\[email protected]\r\n...'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

The question is why the exception is raised and what is this WebKitFormBoundary business?

Edit 2 So, when I print the POST request on my server-side, I do get the data:

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

which returns the following in my console:

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

But, when I post the request.body, I get:

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\[email protected]\r\n------WebKitFormBoundaryG87zmkiNu0fTWY0g\r\n...'

So, does this tell us that the data is making its way to the server-side, and there is a problem retrieving the data?

Upvotes: 0

Views: 281

Answers (1)

mahyar
mahyar

Reputation: 571

i think your problem is in the data that you post in your javascript code, you are not sending a json object to your server but a form object theFormData = new FormData(theForm);

if you want to post a json object you should first create a javascript object then use JSON.stringyfy method on it to create a json and send that json to your server

for example

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

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

Upvotes: 1

Related Questions