Tạo tệp để tải xuống bằng Django


96

Có thể tạo một kho lưu trữ zip và đề nghị tải xuống, nhưng vẫn không lưu tệp vào ổ cứng?

Câu trả lời:


111

Để kích hoạt tải xuống, bạn cần đặt Content-Dispositiontiêu đề:

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

Nếu bạn không muốn tệp trên đĩa, bạn cần sử dụng StringIO

import cStringIO as StringIO

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

Theo tùy chọn, bạn cũng có thể đặt Content-Lengthtiêu đề:

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

1
Tôi nghĩ Content-Length có thể xảy ra tự động với Django middleware
andrewrk

4
Sử dụng ví dụ này tải xuống một tệp luôn trống, có ý kiến ​​gì không?
camelCase

3
Như @ eleaz28 đã nói, nó cũng đang tạo các tệp trống trong trường hợp của tôi. Tôi vừa gỡ bỏ FileWrapper, và nó đã hoạt động.
Sébastien Deprez

Câu trả lời này không hoạt động với Django 1.9: hãy xem điều này: stackoverflow.com/a/35485073/375966
Afshin Mehrabani

1
Tôi đã mở tệp của mình ở chế độ đọc thì tệp.getvalue () đang báo lỗi thuộc tính: TextIOWrapper không có thuộc tính getValue.
Shubham Srivastava

26

Bạn sẽ hạnh phúc hơn khi tạo một tệp tạm thời. Điều này tiết kiệm rất nhiều bộ nhớ. Khi bạn có nhiều hơn một hoặc hai người dùng đồng thời, bạn sẽ thấy việc tiết kiệm bộ nhớ là rất rất quan trọng.

Tuy nhiên, bạn có thể ghi vào một đối tượng StringIO .

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

Đối tượng "bộ đệm" có dạng tệp với tệp nén ZIP 778 byte.


2
Điểm tốt về tiết kiệm bộ nhớ. Nhưng nếu sử dụng một tệp tạm thời, bạn sẽ đặt mã ở đâu để xóa nó?
andrewrk

@ superjoe30: công việc dọn dẹp định kỳ. Django đã có một lệnh quản trị phải được chạy định kỳ để xóa các phiên cũ.
S.Lott

@ superjoe30 đó là những gì / tmp dành cho :)
aehlke

@ S.Lott Có thể cung cấp tệp đã tạo (z trong ví dụ của bạn) bằng cách sử dụng mod x-sendfile không?
Miind

10

Tại sao không tạo một tệp tar thay vào đó? Như vậy:

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
Đối với phiên bản mới hơn của Django, bạn nên có content_type=thay vìmimetype=
Guillaume Lebreton

9

Có, bạn có thể sử dụng mô-đun zipfile , mô-đun zlib hoặc các mô-đun nén khác để tạo tệp nén zip trong bộ nhớ. Bạn có thể làm cho chế độ xem của mình ghi lưu trữ zip vào HttpResponseđối tượng mà chế độ xem Django trả về thay vì gửi ngữ cảnh đến một mẫu. Cuối cùng, bạn sẽ cần đặt mimetype thành định dạng thích hợp để yêu cầu trình duyệt coi phản hồi như một tệp .


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)

Có vẻ không an toàn khi tạo chuỗi kích thước hình ảnh trong bộ nhớ.
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

Bạn có thể thay thế loại zip và nội dung theo yêu cầu của bạn.


1
Ý bạn làfsock = open(filePath,"rb")
stelios

4

Tương tự với trong kho lưu trữ tgz bộ nhớ:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.