Django: in_memory_zip di più in_memory_files
Il concetto base è di non creare file su disco,
ma utilizzare file in_memory.
Dovranno essere “volanti” quindi, sia i file
da zippare, sia il file zip stesso, che verrà
in seguito servito da django.
Semplifichiamo il tutto:
ho una funzione che genera lo zip:
from zipfile import ZipFile from StringIO import StringIO def zip_files(): zip_sio = StringIO() zip_file = ZipFile(zip_sio, 'w') for line in ['a', 'b', 'c', 'd']: name = 'file_{}.txt'.format(line) outfile = StringIO() outfile.write(line) zip_file.writestr(name, outfile.getvalue()) outfile.close() zip_file.close() zip_sio_data = zip_sio.getvalue() zip_sio.close() return zip_file, zip_sio_data
chiaramente potrebbe essere più complesso, ad esempio una
funzione che prenda in ingresso un file, lo splitti in
più parti le quali vengano restituite sotto forma di zip…
from zipfile import ZipFile from StringIO import StringIO def zip_files(file_in): for line in file_in.readlines(): ...
In pratica utilizziamo degli oggetti StringIO, ovvero oggetti File-like,
all’interno dei quali possiamo scrivere delle stringhe, con il metodo ‘write’,
proprio come gli oggetti file.
Con il metodo ‘getvalue’, otteniamo tutto il contenuto dell’oggetto, che una
volta chiuso con ‘close’, non è più accessibile. Per questo motivo lo inseriamo
all’interno del file-like object zip prima di chiuderlo.
Gli stessi dati del file zip, li memorizziamo prima di chiudere lo stesso flie-like
zip, in modo da poterli avere disponibili ad esempio nella view di django
prima di costruire il ‘response’…
comunque nel nostro esempio avremo:
>>> z, data = zip_files() >>> [o.filename for o in z.filelist] ['file_a.txt', 'file_b.txt', 'file_c.txt', 'file_d.txt'] >>> len(data) 410
Come già detto, ‘data’ tornerà utile quando con django andremo a servire il file zip
per il download, ad es.:
... def a_view(request): if request.method == "POST": form = a_form(request.POST, request.FILES) if form.is_valid(): file_in = request.FILES['a_form_file_field'] zip_file, data = zip_file() # or zip_file(file_in) if you process a file response = HttpResponse(data, content_type="application/x-zip-compressed") response['Content-Disposition'] = 'attachment; filename=a_file_zip.zip' return response else: form = a_form() return render(request, 'a_template.html', {'form': form})
Con questo sistema, non scriveremo nessun file sul server.
Commenti recenti