Django带复选框的CSV下载问题:表单清空与URL跳转无法获选中值
解决选中条目导出CSV的表单问题
问题背景
需要导出页面中复选框选中的条目为CSV文件,现有两种方案均存在问题:
- 表单提交方案:能获取选中值,但提交后表单被清空,无法再次下载
- URL跳转方案:无法获取复选框选中值,因为表单未提交
复选框代码:
<td><input type="checkbox" name="checked" value="{{ row.CI }}" class="checkboxAll"></td>
可行解决方案
方案1:表单提交+新窗口打开(保留原页面状态)
给表单添加target="_blank"属性,让表单在新窗口提交处理下载,原页面的复选框状态不会被清空,可多次点击下载。
修改后的表单按钮代码:
<!-- 确保form标签添加target="_blank" --> <form method="GET" target="_blank"> <!-- 其他表单内容 --> <button type="submit" class="btn" value="csv_download" name="csv_download"> <i class="fa-solid fa-file-csv" style="padding-left: 5px; font-size: 9px;"></i> csv_form </button> </form>
视图代码调整(确保过滤选中条目):
def v_base(request): if request.GET.get('csv_download'): checked = request.GET.getlist('checked') response = download_csv(request, checked) return response def download_csv(request, checked=None): checked = checked or request.GET.getlist('checked') db_sel_columns, column = get_column_selected(request) # 仅保留选中的条目 rows = Vbase.objects.filter(CI__in=checked).values(*db_sel_columns) rows_filter = baseFilter(request.GET, queryset=rows) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=download.csv' writer = csv.writer(response) writer.writerow(db_sel_columns) for row in rows_filter.qs: writer.writerow([row['CI'], row['Description']]) return response
方案2:JavaScript收集选中值,拼接GET参数跳转
通过JS获取所有选中的复选框值,拼接到下载URL的查询参数中,跳转后视图可正常获取checked值。
修改后的按钮代码:
<button type="button" class="btn" onclick="downloadSelectedCsv()"> <i class="fa-solid fa-file-csv" style="padding-left: 5px; font-size: 9px;"></i> csv_download </button> <script> function downloadSelectedCsv() { // 获取所有选中的复选框 const checkedItems = document.querySelectorAll('input[name="checked"]:checked'); // 提取选中值组成数组 const checkedValues = Array.from(checkedItems).map(item => item.value); // 拼接原有查询参数 const existingParams = new URLSearchParams(window.location.search); checkedValues.forEach(val => existingParams.append('checked', val)); // 生成下载URL并打开新窗口 const downloadUrl = "{% url 'download_csv' %}?" + existingParams.toString(); window.open(downloadUrl, '_blank'); } </script>
视图代码保持原逻辑即可:
def download_csv(request): checked = request.GET.getlist('checked') db_sel_columns, column = get_column_selected(request) rows = Vbase.objects.filter(CI__in=checked).values(*db_sel_columns) rows_filter = baseFilter(request.GET, queryset=rows) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=download.csv' writer = csv.writer(response) writer.writerow(db_sel_columns) for row in rows_filter.qs: writer.writerow([row['CI'], row['Description']]) return response
方案3:AJAX无刷新下载
如果需要页面无刷新完成下载,可通过AJAX请求获取CSV内容,再通过Blob创建下载链接:
JS代码:
<button type="button" class="btn" onclick="downloadSelectedCsvAjax()"> <i class="fa-solid fa-file-csv" style="padding-left: 5px; font-size: 9px;"></i> csv_ajax </button> <script> function downloadSelectedCsvAjax() { const checkedItems = document.querySelectorAll('input[name="checked"]:checked'); const checkedValues = Array.from(checkedItems).map(item => item.value); const formData = new FormData(); checkedValues.forEach(val => formData.append('checked', val)); // 添加原有查询参数 const existingParams = new URLSearchParams(window.location.search); existingParams.forEach((val, key) => formData.append(key, val)); fetch("{% url 'download_csv' %}", { method: 'POST', body: formData, headers: { 'X-CSRFToken': '{{ csrf_token }}' // Django需携带CSRF令牌 } }).then(response => response.blob()) .then(blob => { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'download.csv'; document.body.appendChild(a); a.click(); // 清理临时链接 URL.revokeObjectURL(url); document.body.removeChild(a); }); } </script>
视图修改为支持POST请求:
from django.views.decorators.csrf import csrf_exempt @csrf_exempt def download_csv(request): # 兼容GET和POST方式获取选中值 if request.method == 'POST': checked = request.POST.getlist('checked') else: checked = request.GET.getlist('checked') db_sel_columns, column = get_column_selected(request) rows = Vbase.objects.filter(CI__in=checked).values(*db_sel_columns) rows_filter = baseFilter(request.GET if request.method == 'GET' else request.POST, queryset=rows) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=download.csv' writer = csv.writer(response) writer.writerow(db_sel_columns) for row in rows_filter.qs: writer.writerow([row['CI'], row['Description']]) return response
内容的提问来源于stack exchange,提问作者user625079
相关产品推荐
相关产品推荐

