Q:

Upload unknown numbers (dynamically decided) of files under Django framework

I encountered an issue: if I want to apply this dynamically rows adding bootstrap code(ref here bootstrap) , I won't be knowing how many files user will upload in advance.(Although I define a maximum of numbers of files allowed to be uploaded:10)
I am using Django 2.1.5.
I have tried to write something like UploadFileForm in form.py, but in that way, I needed to write exactly 10 form.Charfield inside the class, which I am not willing to see.
<form action="" method="post" enctype="multipart/form-data" id="bookform">
    {% csrf_token %}
    <table id="createBookTable" class=" table order-list">
        <thead>
            <tr>
                <td>book title(in original lang.)</td>
                <td>author(in original lang.)</td>
                <td>book title(in Eng.)</td>
                <td>author(in Eng.)</td>
                <td>book image</td>
            </tr>
        </thead>
        <tbody>
              <tr style="display:none">
                <td colspan="5" style="text-align: left;" >
                    <input type="text" id="counter" name="counter" value=""/>
                </td>

            </tr>
            <tr class="bookTr" id="bookTr-0">
                <td class="col-sm-3">
                    <input type="text" name="orginBookname0" class="form-control" />
                </td>
                <td class="col-sm-3">
                    <input type="mail" name="originAuthor0"  class="form-control"/>
                </td>
                <td class="col-sm-3">
                    <input type="text" name="engBookname0"  class="form-control"/>
                </td>
                <td class="col-sm-3">
                    <input type="text" name="engAuthor0"  class="form-control"/>
                </td>
                <td>
                    <input type="file" name="bookimg0">
                </td>
                <td class="col-sm-1"><a class="deleteRow"></a>

                </td>

            </tr>

        </tbody>
        <tfoot>

            <tr>
                <td colspan="5" style="text-align: left;">
                    <input type="button" class="btn btn-lg btn-block " id="addrow" value="Add Row" />
                </td>
            </tr>
              <tr>
                <td colspan="5" style="text-align: left;">
                    <input  type="submit" name="button" id="bookSubmitBtn" class="btn btn-lg btn-block btn-beautiful" value="Submit">
                </td>
            </tr>
        </tfoot>
    </table>
</form>

These are modified version of the mentioned bootstrap demo example:
var counter = 0;
$("#counter").prop('value',counter);
$("#addrow").on("click", function () {

    if(counter<=9){
        counter++;
        var newRow = $('<tr class="bookTr" id="bookTr-'+counter+'">');
        var cols = "";

        cols += '<td><input type="text" class="form-control" name="orginBookname' + counter + '"/></td>';
        cols += '<td><input type="text" class="form-control" name="originAuthor' + counter + '"/></td>';
        cols += '<td><input type="text" class="form-control" name="engBookname' + counter + '"/></td>';
        cols += '<td><input type="text" class="form-control" name="engAuthor' + counter + '"/></td>';
        cols += '<td><input type="file" name="bookimg' + counter + '"/></td>';
        cols += '<td><input type="button" class="ibtnDel btn btn-md btn-danger "  value="Delete"></td>';
        newRow.append(cols);
        $("table.order-list").append(newRow);

        $("#counter").prop('value',counter);
    }
    else{
        alert("You can only add 10 books per time.");
    }
});

The expected results would be that all files chosen by the users be uploaded to media\photos folder. Again, we are not able to know in advance how many files they will be uploading.
I want to use ajax call at the front-end under Django framework.

A:

I found a way to avoid using form.py but using ajax call.
In settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

In urls.py
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

In models.py
class book(models.Model):
    titleOrigin = models.CharField(max_length=200,null = False)
    authorOrigin = models.CharField(max_length=100,null = True)
    titleEnglish = models.CharField(max_length=200,null = True)
    authorEnglish = models.CharField(max_length=100,null = True)
   bookImgFname = models.CharField(max_length=300,null=True)

In createbook.js(use FormData() function!!!):
function upload(event) {
    event.preventDefault();
    var formdata = new FormData($('#bookform').get(0));
    $.ajax({
            url: '/createbook/',
            type: 'post',
            data: formdata,
            cache: false,
            processData: false,
            contentType: false,
            success: function(data) {
                alert('success');
            }
        });
   return false;
}
$(function() {
    $('#bookform').submit(upload);
});

In views.py, use FileSystemStorage and request.FILES['bookimg'+str(i)](thanks to this tutorial)
def createbook(request):
   if request.method == 'POST' and request.is_ajax():

      for i in range(int(request.POST.get('counter'))+1): **#the nondisplayed counter is a trick**

         curOrginBookname = request.POST.get('orginBookname'+str(i))
         curOriginAuthor = request.POST.get('originAuthor'+str(i))
         curEngBookname = request.POST.get('engBookname'+str(i))
         curEngAuthor = request.POST.get('engAuthor'+str(i))
         curBookimg = request.FILES['bookimg'+str(i)]
         fss = FileSystemStorage()
         concatenatedFname = curOrginBookname+"_"+curBookimg.name
         fss.save("photos\\"+concatenatedFname, curBookimg)
         bookToBeSaved = book(titleOrigin=curOrginBookname,authorOrigin=curOriginAuthor,
                              titleEnglish=curEngBookname,authorEnglish=curEngAuthor,bookImgFname=concatenatedFname)
         bookToBeSaved.save()

      return HttpResponse('')

   else:

      return render(request, "createbook.html", locals())

remember to import this:
from django.core.files.storage import FileSystemStorage

