Django के साथ डाउनलोड करने के लिए फ़ाइल जनरेट करना


96

क्या ज़िप संग्रह बनाना और उसे डाउनलोड करने की पेशकश करना संभव है, लेकिन फिर भी हार्ड ड्राइव पर फ़ाइल सहेजना नहीं है?

जवाबों:


111

डाउनलोड को ट्रिगर करने के लिए आपको 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
मुझे लगता है कि सामग्री-लंबाई स्वचालित रूप से Django मिडलवेयर के साथ हो सकती है
andrrk

4
इस उदाहरण का उपयोग करके एक फ़ाइल डाउनलोड की जाती है जो हमेशा खाली होती है, कोई विचार?
कैमलकेस

3
जैसा कि @ eleaz28 ने कहा, यह मेरे मामले में भी रिक्त फाइलें बना रहा था। मैंने बस हटा दिया FileWrapper, और यह काम किया।
सेबास्टियन डेप्रेज़

यह जवाब Django 1.9 के साथ काम नहीं करता है: इसे देखें: stackoverflow.com/a/35485073/375966
Afshin Mehrabani

1
मैंने अपनी फ़ाइल को रीड मोड में खोला, तो file.getvalue () विशेषता त्रुटि दे रहा है: TextIOWrapper में कोई विशेषता नहीं है।
शुभम श्रीवास्तव

26

आप एक अस्थायी फ़ाइल बनाते हुए अधिक खुश होंगे। यह बहुत सारी मेमोरी को बचाता है। जब आपके पास एक या दो से अधिक उपयोगकर्ता समवर्ती होते हैं, तो आप पाएंगे कि मेमोरी की बचत बहुत महत्वपूर्ण है।

हालाँकि, आप स्ट्रिंग स्ट्रिंग ऑब्जेक्ट पर लिख सकते हैं ।

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

"बफर" ऑब्जेक्ट 778 बाइट ज़िप संग्रह के साथ फ़ाइल की तरह है।


2
स्मृति को बचाने के बारे में अच्छी बात है। लेकिन अगर एक अस्थायी फ़ाइल का उपयोग कर रहे हैं, तो आप इसे हटाने के लिए कोड कहां डालेंगे?
andrrk

@ superjoe30: आवधिक सफाई नौकरियां। Django में पहले से ही एक व्यवस्थापक कमांड है जिसे पुराने सत्रों को हटाने के लिए समय-समय पर चलाया जाना चाहिए।
एस.लॉट

@ superjoe30 कि क्या / tmp के लिए है :)
aehlke

@ S.Lott क्या mod x-sendfile का उपयोग करके बनाई गई फ़ाइल (आपके उदाहरण में z) की सेवा करना संभव है?
मिंद

10

इसके बजाय टार फाइल क्यों नहीं बनाते? इस तरह:

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

हां, आप मेमोरी में जिप आर्काइव बनाने के लिए जिपफाइल मॉड्यूल , ज्लीब मॉड्यूल या अन्य कंप्रेशन मॉड्यूल का उपयोग कर सकते हैं । आप अपने विचार को ज़िप संग्रह को उस HttpResponseवस्तु पर लिख सकते हैं जिसे Django दृश्य एक टेम्प्लेट में संदर्भ भेजने के बजाय लौटाता है। अंत में, आपको फ़ाइल के रूप में प्रतिक्रिया का इलाज करने के लिए ब्राउज़र को बताने के लिए उपयुक्त प्रारूप में सेट करना होगा ।


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)

छवि आकार की इन-मेमोरी स्ट्रिंग बनाने के लिए असुरक्षित दिखता है।
ढिल


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

आप अपनी आवश्यकता के अनुसार ज़िप और सामग्री प्रकार बदल सकते हैं।


1
आपका मतलब थाfsock = open(filePath,"rb")
स्टेलियोस

4

मेमोरी tgz संग्रह के साथ भी:

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.