MarkoBox
MarkoBox

Reputation: 95

Writing in memory zip file to django FileField

Im trying to read files from FileField, put them all to zip and save that zip to another FileField. Im trying to avoid using temp file but it seems that i might have to.

Here is what i got so far:

def generate_codified_batch(modeladmin, request, queryset):
    for batch in queryset:
        pieces = Pieces.objects.filter(batch=batch)
        mem_zip = InMemoryZipFile(file_name=batch.name)
        for piece in pieces:
            in_file = open(piece.file.path, 'rb')
            data = in_file.read()
            mem_zip.append(filename_in_zip=f'/{piece.folder_assigned}    /{piece.period}/{piece.codification}. \
                         {piece.file_name.rsplit(".")[-1]}'
                           , file_contents=data)
            in_file.close()
        files_codified = ContentFile(mem_zip.data)
        Batches.objects.filter(pk=batch.id).update(file_codified=files_codified)

InMemoryZipFile is a class from this packet: https://bitbucket.org/ruamel/std.zipfile/src/faa2c8fc9e0072f57857078059ded42192af5435/init.py?at=default&fileviewer=file-view-default#init.py-57

Important are only two last lines

files_codified = ContentFile(mem_zip.data)
Batches.objects.filter(pk=batch.id).update(file_codified=files_codified)

mem_zip.data is a property of InMemoryZip and returns bytes object (from InMemoryZip class):

self.in_memory_data = StringIO()
@property    
def data    
     return self.in_memory_data.getvalue()

I cannot for the life of me figure out how to read from that bytes object and pass it to FileField.

Upvotes: 1

Views: 2069

Answers (1)

dirkgroten
dirkgroten

Reputation: 20692

To assign an in-memory file to a FileField of a Model, you can should use InMemoryUploadedFile or even easier, its subclass SimpleUploadedFile.

Also you should not use a QuerySet's update() function because that only performs the database query but doesn't call a model's save() method which is what saves the file to disk:

So in your code do this:

files_codified = SimpleUploadedFile.from_dict({
    'content': mem_zip.data, 
    'filename': batch.name + ".zip", 
    'content-type': 'application/zip'})
batch.files_codified = files_codified
batch.save()

Upvotes: 5

Related Questions