Reputation: 95
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
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