python हणज Django में गतिशील रूप से जेनरेट किए गए ज़िप अभिलेखागार की सेवा




भारतीय राष्ट्रीय अभिलेखागार की स्थापना (8)

ऐसा करने के लिए यहां एक Django दृश्य है:

import os
import zipfile
import StringIO

from django.http import HttpResponse


def getfiles(request):
    # Files (local path) to put in the .zip
    # FIXME: Change this (get paths from DB etc)
    filenames = ["/tmp/file1.txt", "/tmp/file2.txt"]

    # Folder name in ZIP archive which contains the above files
    # E.g [thearchive.zip]/somefiles/file2.txt
    # FIXME: Set this to something better
    zip_subdir = "somefiles"
    zip_filename = "%s.zip" % zip_subdir

    # Open StringIO to grab in-memory ZIP contents
    s = StringIO.StringIO()

    # The zip compressor
    zf = zipfile.ZipFile(s, "w")

    for fpath in filenames:
        # Calculate path for file in zip
        fdir, fname = os.path.split(fpath)
        zip_path = os.path.join(zip_subdir, fname)

        # Add file, at correct path
        zf.write(fpath, zip_path)

    # Must close zip for all contents to be written
    zf.close()

    # Grab ZIP file from in-memory, make response with correct MIME-type
    resp = HttpResponse(s.getvalue(), mimetype = "application/x-zip-compressed")
    # ..and correct content-disposition
    resp['Content-Disposition'] = 'attachment; filename=%s' % zip_filename

    return resp

Django में उपयोगकर्ताओं को गतिशील रूप से जेनरेट किए गए ज़िप संग्रह की सेवा कैसे करें?

मैं एक साइट बना रहा हूं, जहां उपयोगकर्ता उपलब्ध पुस्तकों का कोई संयोजन चुन सकते हैं और उन्हें ज़िप संग्रह के रूप में डाउनलोड कर सकते हैं। मुझे चिंता है कि प्रत्येक अनुरोध के लिए ऐसे अभिलेखागार उत्पन्न करने से मेरा सर्वर क्रॉल हो जाएगा। मैंने यह भी सुना है कि Django वर्तमान में गतिशील रूप से जेनरेट की गई फ़ाइलों की सेवा के लिए एक अच्छा समाधान नहीं है।


django-zipview प्लग: आप उसी उद्देश्य के लिए django-zipview उपयोग कर सकते हैं।

एक pip install django-zipview बाद pip install django-zipview :

from zipview.views import BaseZipView

from reviews import Review


class CommentsArchiveView(BaseZipView):
    """Download at once all comments for a review."""

    def get_files(self):
        document_key = self.kwargs.get('document_key')
        reviews = Review.objects \
            .filter(document__document_key=document_key) \
            .exclude(comments__isnull=True)

        return [review.comments.file for review in reviews if review.comments.name]

मैं उन अस्थायी ज़िप फ़ाइलों को संग्रहीत करने के लिए अलग मॉडल का उपयोग करने का सुझाव देता हूं। आप ज़िप पर फ्लाई बना सकते हैं, फाइलफील्ड के साथ मॉडल में सहेज सकते हैं और आखिरकार उपयोगकर्ता को यूआरएल भेज सकते हैं।

लाभ:

  • Django मीडिया तंत्र (सामान्य अपलोड की तरह) के साथ स्थैतिक ज़िप फ़ाइलों की सेवा।
  • नियमित क्रॉन स्क्रिप्ट निष्पादन (जो ज़िप फ़ाइल मॉडल से दिनांक फ़ील्ड का उपयोग कर सकते हैं) द्वारा बाली ज़िप फ़ाइलों को साफ़ करने की क्षमता।

यह मॉड्यूल एक संग्रह उत्पन्न करता है और स्ट्रीम करता है: https://github.com/allanlei/python-zipstream

(मैं विकास से जुड़ा नहीं हूं। बस इसका इस्तेमाल करने के बारे में सोच रहा हूं।)


समाधान निम्नानुसार है।

ज़िप संग्रह बनाने के लिए पाइथन मॉड्यूल zipfile का उपयोग करें, लेकिन फ़ाइल के रूप में StringIO ऑब्जेक्ट निर्दिष्ट करें (ZipFile कन्स्ट्रक्टर को फ़ाइल की तरह ऑब्जेक्ट की आवश्यकता है)। उन फ़ाइलों को जोड़ें जिन्हें आप संपीड़ित करना चाहते हैं। फिर अपने Django एप्लिकेशन में HttpResponse में StringIO ऑब्जेक्ट की सामग्री को माइमटाइप सेट के साथ application/x-zip-compressed (या कम से कम application/octet-stream ) पर सेट करें। यदि आप चाहते हैं, तो आप content-disposition शीर्षलेख सेट कर सकते हैं, लेकिन यह वास्तव में आवश्यक नहीं होना चाहिए।

लेकिन सावधान रहें, प्रत्येक अनुरोध पर ज़िप अभिलेखागार बनाना बुरा विचार है और यह आपके सर्वर को मार सकता है (अभिलेखागार बड़े होने पर टाइमआउट की गणना नहीं कर रहा है)। प्रदर्शन-वार दृष्टिकोण फाइल सिस्टम में कहीं भी उत्पन्न आउटपुट को कैश करना है और केवल तब ही पुन: उत्पन्न करना है जब स्रोत फ़ाइलों को बदल दिया गया हो। यहां तक ​​कि बेहतर विचार है कि अभिलेखागार अग्रिम में तैयार करें (उदाहरण के लिए क्रॉन जॉब द्वारा) और अपना वेब सर्वर सामान्य स्टेटिक्स के रूप में उनकी सेवा कर रहा है।


पायथन 3 के लिए मैं io.ByteIO का उपयोग करता हूं क्योंकि स्ट्रिंगियो को इसे प्राप्त करने के लिए बहिष्कृत किया गया है। आशा करता हूँ की ये काम करेगा।

import io

def my_downloadable_zip(request):
    zip_io = io.BytesIO()
    with zipfile.ZipFile(zip_io, mode='w', compression=zipfile.ZIP_DEFLATED) as backup_zip:
        backup_zip.write('file_name_loc_to_zip') # u can also make use of list of filename location
                                                 # and do some iteration over it
     response = HttpResponse(zip_io.getvalue(), content_type='application/x-zip-compressed')
     response['Content-Disposition'] = 'attachment; filename=%s' % 'your_zipfilename' + ".zip"
     response['Content-Length'] = zip_io.tell()
     return response

Django सीधे गतिशील सामग्री की पीढ़ी को संभाल नहीं करता है (विशेष रूप से ज़िप फ़ाइलें)। वह काम पायथन की मानक पुस्तकालय द्वारा किया जाएगा। आप पाइथन में गतिशील रूप से ज़िप फ़ाइल बनाने के तरीके को देख सकते हैं।

यदि आप इसके सर्वर को धीमा करने के बारे में चिंतित हैं तो आप अनुरोधों को कैश कर सकते हैं यदि आप एक ही अनुरोध के लिए अपेक्षा करते हैं। आप इसके साथ मदद करने के लिए Django के कैश ढांचे का उपयोग कर सकते हैं।

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


यहां कई जवाब एक StringIO या BytesIO बफर का उपयोग करने का सुझाव देते हैं। हालांकि इसकी आवश्यकता नहीं है क्योंकि HttpResponse पहले से ही एक फ़ाइल जैसी वस्तु है:

response = HttpResponse(content_type='application/zip')
zip_file = zipfile.ZipFile(response, 'w')
for filename in filenames:
    zip_file.write(filename)
response['Content-Disposition'] = 'attachment; filename={}'.format(zipfile_name)
return response




django