Send data with POST request to Django backend with AJAX

Hello everyone, I’m quite a newbie in terms of Django and coding.

I tried to using ajax with post method to send multiple inputs (multiple rows) of the table (in tag) to the backend. However, using .save() method only transferred one record (the last row) to the database.

I check the data in console.log() that AJAX did sending a JSON array to the backend (SerilializeArray()) then I checked for the data after processed by .save() method, it only contained the data from the last field…

Can someone give me a hand on this? I’ve been wasting time on this…

We’ll be happy to try, but it’s all going to need to start with you posting the relevant code - both the JavaScript and the Django view.

A little more detail about the Django side may be useful. What versions of Python and Django? Are there any third-party libraries that are part of this? (e.g. Django Rest Framework)

It would also be helpful to see the smallest example of what’s being sent from the browser. You mention multiple inputs but only saving the last one. If a sample size of 2 rows would also demonstrate that behavior, that would be fine.

When posting code here, please enclose it between lines of three backtick - ` characters. You’ll have a line of ```, then your code, then another line of ```. This forces the forum software to keep your code formatted correctly, which is critical with Python.

:joy: Sorry… I’m not quite sure whether I can explain the problem clearly but allow me to give it a shot. English is my secondary language so please bear with me…

Here is some background information: I was trying to construct a small webpage for internal use, in which my colleagues can fill in the blank table and the data they inputted would be transferred to the backend using Django framework.

system: windows 10
django framework: 3.9.2
python: 3.9.6

Therefore, I constructed my view as the following:

# view.py
import ...

def post_form(request):
    # check whether the request is ajax request and whether the method is post
    if request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' and request.method == 'POST':
        form = evaluation_fee_form(request.POST)
        if form.is_valid():
            form.save()
            test = request.POST
            return JsonResponse({"instance": "saved successfully",
                                 "form_isbound" : form.is_bound,
                                 "django_backend": test}, status=200)
        else:
            return JsonResponse({"error": "error occurred"}, status=400)

    return JsonResponse({"error": "Not AJAX request or Wrong request method"}, status=500)

the evaluation_fee_form was a modelForm subclass of the model evaluation_fee

# models.py
from django.db import models

class evaluation_fee(models.Model):

    branch_name = models.CharField(max_length=5, blank=True)
    sheet_no = models.CharField(max_length=10, blank=True)
    fee = models.CharField(max_length=50, blank=True)
    contract_no = models.TextField(null=True, blank=True)
    client_id = models.TextField(null=True, blank=True)
    notes = models.TextField(null=True, blank=True)

    def __str__(self):
        return self.branch_name
# forms.py
from django import forms
from .models import evaluation_fee


class evaluation_fee_form(forms.ModelForm):

    class Meta:
        model = evaluation_fee
        fields = ("__all__")
        widgets = {
            'contract_no': forms.TextInput,
            'client_id': forms.TextInput,
            'notes': forms.TextInput,
        }

and finally I had my html body as:

<html>
... some stylesheet...
<body>
... some other things...
          <div class="table-responsive">
              <form id="post_form">
                  {% csrf_token %}
                  <table class="table caption-top" id="post_table">
                      <caption style="font-size:36px">table title</caption>
                      <thead>
                        <tr>
                          {% for field in form %}
                          <th>{{ field.label }}</th>
                          {% endfor %}
                      </tr>
                      </thead>
                      <tbody>
                        <tr>
                            {% for field in form %}
                          <td>
                              {{ field }}
                          </td>
                            {% endfor %}
                        </tr>
                        <tr>
                            {% for field in form %}
                          <td>
                              {{ field }}
                          </td>
                            {% endfor %}
                        </tr>
                        <tr>
                            {% for field in form %}
                          <td>
                              {{ field }}
                          </td>
                            {% endfor %}
                        </tr>
                      </tbody>
                  </table>
                  <input type="submit" class="btn btn-primary" value="submit">
              </form>
          </div>
</body>
... importing jQuery script...
    <script type="text/javascript">
      $(document).ready(function () {
              $('#post_form').submit(function(i){
              //first prevent the page from reloading and all other default actions
              i.preventDefault();
              var serializedData = $(this).serializeArray();
              //make POST ajax call
              $.ajax({
                  method:'POST',
                  url: "/post_form/ajax/form/",
                  data: serializedData,
                  success: function (response, django_backend, form_isbound) {
                      $("#post_form").trigger('reset');
                      console.log(serializedData);
                      console.log(response);
                      console.log(django_backend);
                      console.log(form_isbound);
                      alert("done!");
                      },
                  error: function (response) {
                      alert(response["responseJSON"]["error"]);
                  }
              })
          })
      })
    </script>
</html>

After I reviewed my code yesterday and I’m now having the assumption on the

...
                        <tr>
                            {% for field in form %}
                          <td>
                              {{ field }}
                          </td>
                            {% endfor %}
                        </tr>
...

of the html file: The intention of this bite of code was to build a table with 3 rows * 9 columns with 27 input “cells” like what we see in the MS excel but since I’m using the for loop, the <input> fields in every rows were sharing the same "name" attribute like:

<tr>
 <td>
   <input type="text" name="notes" class="table-responsive" id="id_notes">
 </td>
</tr>
<tr>
 <td>
   <input type="text" name="notes" class="table-responsive" id="id_notes">
 </td>
</tr>

In this way, the data transferred using request.POST retrieve only the last row of the input since the input with the same name overwrote the previous. Hence, the records in sqlite 3 database recored an empty record.

What I put in the table:

num contract
1 W3324
2 W3314
3 S3304

sqlite 3 database:

num contract
3 S3304

Then, I manually changed the <name> attributes as the following:

<tr>
 <td>
   <input type="text" name="notes" class="table-responsive" id="id_notes">
 </td>
</tr>
<tr>
 <td>
   <input type="text" name="notes2" class="table-responsive" id="id_notes">
 </td>
</tr>

This time, the data transferred using request.POST retrieve whatever I put but the sqlite 3 database recored only the input filed with name = what I’ve defined in the model:

What I put in the table:

num contract
1 W3324
2 W3314
3 S3304

sqlite 3 database:

num contract
1 W3324

What I want is something like:

num contract
1 W3324
2
3 S3304

(yes, the third row is left in blank on purpose)

sqlite 3 database:

num contract
1 W3324
2 W3314
3 S3304

Any help is appreciated, thank you.

Ok, so the real issue here is that you are trying to work with multiple instances of the same form on a page. You’re not working with one form, you want to be working with a list of forms - each one being a separate form.

The Django facility you’re looking for are Formsets.

Thank you, Let me have a look at it now :grinning:

Hi Mr.Whitesell,

Thank you so much for pointing me a right direction, my form finally worked! :laughing: