Django: Copy FileFields
Asked Answered
L

2

5

I'm trying to copy a file using a hardlink, where the file is stored as a Django FileField. I'd like to use a hardlink to save space and copy time (no changes are expected to be made to the original file or copy). However, I'm getting some odd errors when I try to call new_file.save() from the snippet below.

AttributeError: 'file' object has no attribute '_committed'

My thinking is that after making the hardlink, I can just open the linked file and store it to the Django new File instance's FileFile. Am I missing a step here or something?

models.py

class File(models.Model):
    stored_file = models.FileField()

elsewhere.py

import os 

original_file = File.objects.get(id=1)
original_file_path = original_file.file.path

new_file = File()
new_file_path = '/path/to/new/file'

os.makedirs(os.path.realpath(os.path.dirname(new_file_path)))
os.link(original_file_path, new_file_path)
new_file.stored_file = file(new_file_path)
new_file.save()
Livonia answered 10/4, 2012 at 16:7 Comment(0)
W
11

There is no need to create hardlink, just duplicate the file holder:

new_file = File(stored_file=original_file.stored_file)
new_file.save()

update

If you want to specify file to FileField or ImageField, you could simply

new_file = File(stored_file=new_file_path)
# or
new_file = File()
new_file.stored_file = new_file_path
# or
from django.core.files.base import File
# from django.core.files.images import ImageFile # for ImageField
new_file.stored_file = File(new_file_path)

the field accepts path in basestring or File() instance, the code in your question uses file() and hence is not accepted.

Wolter answered 10/4, 2012 at 16:58 Comment(2)
Thanks for your response okm. The reason I chose the hard-link is because I'd like store a different file path with the new File() instance. I guess that requirement is not evident in the snippet above - I tried to simplify it as much as possible - but I'm creating the filename based on a uuid associated with the File() model instance. When I copy the File() model instance, I'd like the underlaying stored_file path to match the new File() instance's uuid. That's why I gravitated towards the hard-link.Livonia
@JoeJ I see, then your answer is correct. updated my answer as wellWolter
L
2

I think I solved this issue, but not sure why it works. I wrapped the file object in a "DjangoFile" class (I imported as DjangoFile to avoid clashing with my previously defined File model).

from django.core.files.base import File as DjangoFile

...
new_file.stored_file = DjangoFile(file(new_file_path))
new_file.save()

This approached seemed to save the file OK.

Livonia answered 10/4, 2012 at 23:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.