django 实现指定文件合并成压缩文件下载
需求是在一列学生列表中选择指定的学生,然后下载他们上传的报告文档。
用Js构造一个表单将选中的学生学号传递到后台
$('#output_student').click(function () { var arr = new Array(); var sign = 0; var inputs = document.getElementsByTagName('input');//获取所有的input标签对象。 for (var i = 0; i < inputs.length; i++) { var obj = inputs[i]; if (obj.type == 'checkbox') { if (obj.checked == true) { sign = 1; var length = arr.push(obj.value); } } } if (sign == 0)//没有被选择项 { alert("请勾选要下载的数据!"); return; } if (!confirm("确定下载选中的条目吗?")) return; var form = $("<form>"); form.attr('style', 'display:none'); form.attr('target', ''); form.attr('method', 'post'); form.attr('action', '{% url "teacher:downloadDoc" %}'); var input1 = $('<input>'); input1.attr('type', 'hidden'); input1.attr('name', 'number'); input1.attr('value', arr.join("&")); $('body').append(form); form.append(input1); form.submit(); form.remove(); });
后台接收数据
class DownloadDoc(LoginRequiredMixin, View): login_url = "/" @staticmethod def post(request): try: numbers = request.POST['number'] list_number = numbers.split('&') if "on" in list_number: list_number = list_number[1:] temp = tempfile.TemporaryFile() archive = zipfile.ZipFile(temp, 'w', zipfile.ZIP_DEFLATED) for number in list_number: student = Student.objects.get(number=number) if Document.objects.filter(student=student, period='01'): document = Document.objects.get(student=student, period='01') base_dir = os.path.dirname(os.path.dirname(__file__)) target_file = os.path.join(base_dir, 'static', 'media', str(document.file)).replace('\\', '/') file_name = str(document.file).split('/')[4] archive.write(target_file, student.real_name+"--"+file_name) archive.close() wrapper = FileWrapper(temp) response = HttpResponse(wrapper, content_type='application/zip') response['Content-Disposition'] = 'attachment; filename='+time.strftime('%m-%d')+'.zip' response['Content-Length'] = temp.tell() temp.seek(0) return response except Document.DoesNotExist: return
注解:
temp = tempfile.TemporaryFile()
tempfile.TemporaryFile([mode='w+b'[, bufsize=-1[, suffix=''[, prefix='tmp'[, dir=None]]]]])
该函数返回一个 类文件 对象(file-like)用于临时数据保存(实际上对应磁盘上的一个临时文件)。当文件对象被close或者被del的时候,临时文件将从磁盘上删除。 mode、bufsize参数的单方与open()函数一样;suffix和prefix指定了临时文件名的后缀和前缀;dir用于设置临时文件默认的保 存路径。返回的类文件对象有一个file属性,它指向真正操作的底层的file对象。
注解:
archive = zipfile.ZipFile(temp, 'w', zipfile.ZIP_DEFLATED)
zipfile.ZipFile(fileName[, mode[, compression[, allowZip64]]])
fileName是没有什么疑问的了。
mode和一般的文件操作一样,'r'表示打开一个存在的只读ZIP文件;'w'表示清空并打开一个只写的ZIP文件,或创建一个只写的ZIP文件;'a'表示打开一个ZIP文件,并添加内容。
compression表示压缩格式,可选的压缩格式只有2个:ZIP_STORE;ZIP_DEFLATED。ZIP_STORE是默认的,表示不压缩;ZIP_DEFLATED表示压缩,如果你不知道什么是Deflated,那么建议你去补补课。
allowZip64为True时,表示支持64位的压缩,一般而言,在所压缩的文件大于2G时,会用到这个选项;默认情况下,该值为False,因为Unix系统不支持。
1.2 zipfile.close()
说真的,这个没什么可说的,如果有的话,那就是你写入的任何文件在关闭之前不会真正写入磁盘。
1.3 zipfile.write(filename[, arcname[, compress_type]])
acrname是压缩文件中该文件的名字,默认情况下和filename一样
compress_type的存在是因为zip文件允许被压缩的文件可以有不同的压缩类型。
1.4 zipfile.extractall([path[, member[, password]]])
path解压缩目录,没什么可说的
member需要解压缩的文件名儿列表
password当zip文件有密码时需要该选项
对于简单的应用,这么多就够了。
FileWrapper
简单说就是用FileWrapper类来迭代器化一下文件对象,实例化出一个经过更适合大文件下载场景的文件对象,实现原理相当与把内容一点点从文件中读取,放到内存,下载下来,直到完成整个下载过程。这样内存就不会担心你一下子占用它那么多空间了。