กำลังสร้างไฟล์เพื่อดาวน์โหลดด้วย Django


96

เป็นไปได้ไหมที่จะสร้างไฟล์ zip และเสนอให้ดาวน์โหลด แต่ยังไม่ได้บันทึกไฟล์ลงในฮาร์ดไดรฟ์

คำตอบ:


112

ในการเริ่มการดาวน์โหลดคุณต้องตั้งค่าContent-Dispositionส่วนหัว:

from django.http import HttpResponse
from wsgiref.util import FileWrapper

# generate the file
response = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response

หากคุณไม่ต้องการไฟล์บนดิสก์คุณจำเป็นต้องใช้ StringIO

import cStringIO as StringIO

myfile = StringIO.StringIO()
while not_finished:
    # generate chunk
    myfile.write(chunk)

คุณสามารถเลือกที่จะตั้งค่าContent-Lengthส่วนหัวได้เช่นกัน:

response['Content-Length'] = myfile.tell()

1
ฉันคิดว่า Content-Length อาจเกิดขึ้นโดยอัตโนมัติกับมิดเดิลแวร์ Django
andrewrk

4
การใช้ตัวอย่างนี้ดาวน์โหลดไฟล์ที่ว่างเปล่าเสมอมีความคิดใดบ้าง?
camelCase

3
ดังที่ @ eleaz28 กล่าวว่ามันเป็นการสร้างไฟล์เปล่าในกรณีของฉันด้วย ฉันเพิ่งลบออกFileWrapperและมันใช้งานได้
Sébastien Deprez

คำตอบนี้ใช้ไม่ได้กับ Django 1.9: ดูสิ่งนี้: stackoverflow.com/a/35485073/375966
Afshin Mehrabani

1
ฉันเปิดไฟล์ในโหมดอ่านแล้ว file.getvalue () ให้ข้อผิดพลาดแอตทริบิวต์: TextIOWrapper ไม่มีแอตทริบิวต์ getValue
Shubham Srivastava

25

คุณจะมีความสุขมากขึ้นในการสร้างไฟล์ชั่วคราว ซึ่งจะช่วยประหยัดหน่วยความจำได้มาก เมื่อคุณมีผู้ใช้มากกว่าหนึ่งหรือสองคนพร้อมกันคุณจะพบว่าการประหยัดหน่วยความจำนั้นสำคัญมาก

อย่างไรก็ตามคุณสามารถเขียนลงในวัตถุStringIO

>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())
778

ออบเจ็กต์ "บัฟเฟอร์" เป็นเหมือนไฟล์ที่มีไฟล์ ZIP 778 ไบต์


2
จุดดีเกี่ยวกับการประหยัดหน่วยความจำ แต่ถ้าใช้ไฟล์ชั่วคราวจะเอาโค้ดไปลบที่ไหนครับ?
andrewrk

@ superjoe30: งานล้างข้อมูลเป็นระยะ Django มีคำสั่งผู้ดูแลระบบอยู่แล้วซึ่งต้องเรียกใช้เป็นระยะเพื่อลบเซสชันเก่า

@ superjoe30 นั่นคือสิ่งที่ / tmp มีไว้สำหรับ :)
aehlke

@ S.Lott เป็นไปได้ไหมที่จะให้บริการไฟล์ที่สร้างขึ้น (z ในตัวอย่างของคุณ) โดยใช้ mod x-sendfile?
Amir Afianian

10

ทำไมไม่สร้างไฟล์ tar แทนล่ะ? ชอบมาก:

def downloadLogs(req, dir):
    response = HttpResponse(content_type='application/x-gzip')
    response['Content-Disposition'] = 'attachment; filename=download.tar.gz'
    tarred = tarfile.open(fileobj=response, mode='w:gz')
    tarred.add(dir)
    tarred.close()

    return response

1
สำหรับ Django เวอร์ชันใหม่คุณควรมีcontent_type=แทนmimetype=
Guillaume Lebreton

9

ใช่คุณสามารถใช้โมดูล zipfile , โมดูล zlibหรืออื่น ๆอัดโมดูลเพื่อสร้างไฟล์ zip ในหน่วยความจำ คุณสามารถทำให้มุมมองของคุณเขียนไฟล์ zip ไปยังHttpResponseวัตถุที่มุมมอง Django ส่งกลับแทนที่จะส่งบริบทไปยังเทมเพลต สุดท้ายคุณจะต้องตั้งค่าชนิด mime ในรูปแบบที่เหมาะสมในการบอกเบราว์เซอร์ในการรักษาการตอบสนองเป็นไฟล์


6

Models.py

from django.db import models

class PageHeader(models.Model):
    image = models.ImageField(upload_to='uploads')

views.py

from django.http import HttpResponse
from StringIO import StringIO
from models import *
import os, mimetypes, urllib

def random_header_image(request):
    header = PageHeader.objects.order_by('?')[0]
    image = StringIO(file(header.image.path, "rb").read())
    mimetype = mimetypes.guess_type(os.path.basename(header.image.name))[0]

    return HttpResponse(image.read(), mimetype=mimetype)

ดูไม่ปลอดภัยในการสร้างสตริงขนาดรูปภาพในหน่วยความจำ
dhill


5
def download_zip(request,file_name):
    filePath = '<path>/'+file_name
    fsock = open(file_name_with_path,"rb")
    response = HttpResponse(fsock, content_type='application/zip')
    response['Content-Disposition'] = 'attachment; filename=myfile.zip'
    return response

คุณสามารถเปลี่ยน zip และประเภทเนื้อหาได้ตามความต้องการของคุณ


1
คุณหมายถึงfsock = open(filePath,"rb")
stelios

4

เช่นเดียวกับในหน่วยความจำ tgz archive:

import tarfile
from io import BytesIO


def serve_file(request):
    out = BytesIO()
    tar = tarfile.open(mode = "w:gz", fileobj = out)
    data = 'lala'.encode('utf-8')
    file = BytesIO(data)
    info = tarfile.TarInfo(name="1.txt")
    info.size = len(data)
    tar.addfile(tarinfo=info, fileobj=file)
    tar.close()

    response = HttpResponse(out.getvalue(), content_type='application/tgz')
    response['Content-Disposition'] = 'attachment; filename=myfile.tgz'
    return response
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.