上传文件后,如何在 Django 中使用 AJAX 更新表(与 JavaScript 链接)?

Posted

技术标签:

【中文标题】上传文件后,如何在 Django 中使用 AJAX 更新表(与 JavaScript 链接)?【英文标题】:After uploading file, How to update table (which is linked with JavaScripts) using AJAX in Django? 【发布时间】:2021-05-27 15:46:26 【问题描述】:

在上传文件之前,表格如下所示:

使用 AJAX 上传文件后,需要使用 AJAX 刷新表格(这与一些脚本标签链接):

注意: 这里的主要问题是在AJAX成功请求之后,JavaScripts没有申请tabledata容器。

在views.py中:

@login_required(login_url='/login/')
def upload_csv(request):
form = CsvfileForm(request.POST or None, request.FILES or None)
if form.is_valid():
    user = form.save(commit=False)
    user.author = request.user
    user.file_id = ("FILE" + (uuid.uuid4().hex[:9]).lower())
    user.save()
    form = CsvfileForm()
    obj = CsvFiles.objects.get(Q(activated=False) & Q(on_process=False))
    obj.on_process=True
    obj.save()
    with open(obj.file_name.path,'r') as f:
        reader = csv.reader(f)

        for i, row in enumerate(reader):
            if i==0:
                pass
            else:
                csvdatas.objects.create(
                    file_link = obj,
                    file_id=obj.file_id,
                    author = request.user,
                    data_id=("ABC"+(uuid.uuid4().hex[:9]).lower()),
                    year=row[0],
                    industry_code=row[1],
                    industry_name=row[2],
                    rme_size=row[3],
                    variable=row[4],
                    value=row[5],
                    unit=row[6]
                )

        obj.activated = True
        obj.save()
all_datas = csvdatas.objects.filter(author=request.user)
all_table = CsvFiles.objects.filter(author=request.user)
return render(request,'refreshTable.html',locals())

在 RefreshTable.html 中:

    <legend>Datas</legend>

    <br>
     <div id="alert-box1"></div>
    <br>

    <section id="file_table">
<table id="table_id1" class="display responsive nowrap" style="width=100%;">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Download</th>
            <th>Delete</th>
        </tr>
    </thead>
    <tbody>
    % for i in all_table %
        <tr>
            <td> i.file_id </td>
            <td> i.file_name </td>
            <td> i.uploaded </td>
            <td><a href=" i.file_name.url " target="_blank">Download</a></td>
            <td>
                 <form method="post" action="% url 'deletefile' i.pk %" id="deleteid">
                    % csrf_token %
                     <input type="submit" value="Delete" />
                 </form>
            </td>
        </tr>
    % endfor %
    </tbody>
        <tfoot>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
             <th>Download</th>
            <th>Delete</th>
        </tr>
    </tfoot>
</table>
    </section>
    <br><br>
<form method="POST" enctype="multipart/form-data">
    % csrf_token %
    <div class="ButtonsData"></div>
    <table id="table_id" class="display responsive nowrap" style="width=100%;">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
        </tr>
    </thead>
    <tbody>
    % for i in all_datas %
        <tr>
            <td> i.data_id </td>
            <td> i.year </td>
            <td> i.industry_code </td>
            <td> i.industry_name </td>
            <td> i.rme_size </td>
            <td> i.variable </td>
            <td> i.value </td>
            <td> i.unit </td>
            <td> i.created </td>
        </tr>
    % endfor %
    </tbody>
        <tfoot>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
        </tr>
    </tfoot>
</table>
</form>

在 Profile.html 中(在这个页面中我们只在 AJAX 成功后追加、refreshTable.html):

<body>
<fieldset>
    <div id="alert-box"></div>
    <br>
    <legend>Upload</legend>
<form id="upload-form" method="POST" enctype="multipart/form-data" action="% url 'uploadcsv' %">
    % csrf_token %
    upload_form
    <button type="submit" class="ui button primary">Upload here</button>
</form>
    <div id="progress-box" class="not-visible">
    </div>
</fieldset>
<br>
<br>
<fieldset id="fieldTable">
    <legend>Datas</legend>
    <br>
     <div id="alert-box1"></div>
    <br>
    <section id="file_table">
<table id="table_id1" class="display responsive nowrap" style="width=100%;">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Download</th>
            <th>Delete</th>
        </tr>
    </thead>
    <tbody>
    % for i in all_table %
        <tr>
            <td> i.file_id </td>
            <td> i.file_name </td>
            <td> i.uploaded </td>
            <td><a href=" i.file_name.url " target="_blank">Download</a></td>
            <td>
                 <form method="post" action="% url 'deletefile' i.pk %" id="deleteid">
                    % csrf_token %
                     <input type="submit" value="Delete" />
                 </form>
            </td>
        </tr>
    % endfor %
    </tbody>
        <tfoot>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
             <th>Download</th>
            <th>Delete</th>
        </tr>
    </tfoot>
</table>
    </section>
    <br><br>
<form method="POST" enctype="multipart/form-data">
    % csrf_token %
    <div class="ButtonsData"></div>
    <table id="table_id" class="display responsive nowrap" style="width=100%;">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
        </tr>
    </thead>
    <tbody>
    % for i in all_datas %
        <tr>
            <td> i.data_id </td>
            <td> i.year </td>
            <td> i.industry_code </td>
            <td> i.industry_name </td>
            <td> i.rme_size </td>
            <td> i.variable </td>
            <td> i.value </td>
            <td> i.unit </td>
            <td> i.created </td>
        </tr>
    % endfor %
    </tbody>
        <tfoot>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
        </tr>
    </tfoot>
</table>
</form>
</fieldset>

在 main.js(AJAX 函数)中:

const uploadForm = document.getElementById('upload-form')

const alertBox = document.getElementById('alert-box')
const progressBox = document.getElementById('progress-box')


$('#upload-form').on('submit',function(event)
    event.preventDefault();
    progressBox.classList.remove('not-visible')

    var formData = new FormData($('#upload-form')[0]);

    $.ajax(
        type:'POST',
        url: '/uploadcsv/',
        enctype: 'multipart/form-data',
        data: formData,
        beforeSend: function()
            console.log('before')
            alertBox.innerHTML= ""
        ,
        xhr: function()
            const xhr = new window.XMLHttpRequest();
            xhr.upload.addEventListener('progress', e=>

                if (e.lengthComputable) 
                    const percent = (e.loaded / e.total) * 100
                    progressBox.innerHTML = `<br><div class="progress">
                                                <div class="progress-bar" role="progressbar" style="width: $percent%" aria-valuenow="$percent" aria-valuemin="0" aria-valuemax="100"></div>
                                            </div>
                                            <p>$percent.toFixed(1)%</p><br>`
                

            );

            return xhr
        ,
        success: function(json)
            alertBox.innerHTML = `<div class="alert alert-success" role="alert" style="color:green;">
                                    Successfully uploaded the file.
                                </div>`
            progressBox.classList.add('not-visible')
            $('#fieldTable').empty() //we are empty the container
            $('#fieldTable').append(json) //the response is refreshTable.html, and we append it
        ,
        error: function(error)
            alertBox.innerHTML = `<div class="alert alert-danger" role="alert">
                                    Oops... something went wrong
                                </div>`
            progressBox.classList.add('not-visible')
        ,
        cache: false,
        contentType: false,
        processData: false,
    )
)

在脚本中(这些有数据表脚本链接):

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="% static 'main.js' %" defer></script>
    <script src="% static 'deletefile.js' %" defer></script>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/dt/jszip-2.5.0/dt-1.10.23/b-1.6.5/b-colvis-1.6.5/b-flash-1.6.5/b-html5-1.6.5/b-print-1.6.5/cr-1.5.3/r-2.2.7/sc-2.0.3/sp-1.2.2/sl-1.3.1/datatables.min.js"></script>
<script>
 $(document).ready(function() 

    $('#table_id tfoot th').each( function () 
        var title = $(this).text();
        $(this).html( '<input type="text"  style="width:100%;" placeholder="Search '+title+'" />' );
     );




    $('#table_id').DataTable( 
        responsive: true,
        dom: 'Bfrtip',
        buttons: [
         
                extend: 'copy',
                exportOptions: 
                    columns: ':visible'
                
            ,
            
                extend: 'excel',
                exportOptions: 
                    columns: ':visible'
                
            ,
            
                extend: 'pdf',
                exportOptions: 
                    columns: ':visible'
                
            ,
            
                extend: 'print',
                exportOptions: 
                    columns: ':visible'
                
            ,
            
                extend: 'csv',
                exportOptions: 
                    columns: ':visible'
                
            ,
            'colvis'
            //'copy', 'csv', 'excel', 'pdf', 'print','colvis',
        ],
        initComplete: function () 
            // Apply the search
            this.api().columns().every( function () 
                var that = this;

                $( 'input', this.footer() ).on( 'keyup change clear', function () 
                    if ( that.search() !== this.value ) 
                        that
                            .search( this.value )
                            .draw();
                    
                 );
             );
        
     );
 );
</script>

注意: 这里的主要问题是在AJAX成功请求之后,JavaScripts没有申请tabledata容器。

【问题讨论】:

【参考方案1】:

您可以使用 destroy() 选项 (Datatables docs) 并重新初始化您的表。我也会使用 jQuery .html()

See Live Example

在成功方法中添加以下几行:

$("#fieldTable").html(newHtmlTable);
$('#table_id1').DataTable().destroy()
$('#table_id1').DataTable();
$('#table_id').DataTable().destroy();
$('#table_id').DataTable();

您的 AJAX 方法:

$('#upload-form').on('submit',function(event)
    event.preventDefault();
    progressBox.classList.remove('not-visible')

    var formData = new FormData($('#upload-form')[0]);

    $.ajax(
        type:'POST',
        url: '/uploadcsv/',
        enctype: 'multipart/form-data',
        data: formData,
        beforeSend: function()
            console.log('before')
            alertBox.innerHTML= ""
        ,
        xhr: function()
            const xhr = new window.XMLHttpRequest();
            xhr.upload.addEventListener('progress', e=>

                if (e.lengthComputable) 
                    const percent = (e.loaded / e.total) * 100
                    progressBox.innerHTML = `<br><div class="progress">
                                                <div class="progress-bar" role="progressbar" style="width: $percent%" aria-valuenow="$percent" aria-valuemin="0" aria-valuemax="100"></div>
                                            </div>
                                            <p>$percent.toFixed(1)%</p><br>`
                

            );

            return xhr
        ,
        success: function(newHtmlTable)
            alertBox.innerHTML = `<div class="alert alert-success" role="alert" style="color:green;">
                                    Successfully uploaded the file.
                                </div>`
            progressBox.classList.add('not-visible')
            $("#fieldTable").html(newHtmlTable);
            $('#table_id1').DataTable().destroy()
            $('#table_id1').DataTable();
            $('#table_id').DataTable().destroy();
            $('#table_id').DataTable();
        ,
        error: function(error)
            alertBox.innerHTML = `<div class="alert alert-danger" role="alert">
                                    Oops... something went wrong
                                </div>`
            progressBox.classList.add('not-visible')
        ,
        cache: false,
        contentType: false,
        processData: false,
    )
)

【讨论】:

以上是关于上传文件后,如何在 Django 中使用 AJAX 更新表(与 JavaScript 链接)?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中使用 Ajax 上传图片? Python

Django ajax jquery 文件上传

将通过 ajax 上传的文件保存到 Django 模型 ImageField

带有ajax的django应用程序用于处理数据帧

如何使用 Django 和 AJAX 显示上传的图像

Django中的文件上传+Ajax详细应用