3

How do you change the filename of a media file (user-uploaded file) in Django after it's been saved?

I understand that if you want to do it as it's being uploaded that you can follow the solution in questions like this, but I'm talking about changing the names of images that are already in the database.

I have tried overriding the name attribute of the ImageFileField and then saving the model, but this does not affect the file itself. It just breaks the reference because now the ImageFileField is pointing at the new name but the file still has the old one.

Using the same example model as the linked question:

class SomeModel(models.Model):
    title = models.CharField(max_length=100)
    video = models.FileField(upload_to='video')

This does NOT work:

>>> for m in SomeModel.objects.all():
...   m.video.name = 'new_video_name.avi'
...   m.save()

What should I be doing here?

Community
  • 1
  • 1
Two-Bit Alchemist
  • 17,966
  • 6
  • 47
  • 82

1 Answers1

0

There is no magic and easy way to do it. When you load your object from the database (the for loop), the name of the file referenced by the video attribute is loaded from the database too. You can't just change it and make the underlying file change it's name.

In order to accomplish a name change for both the physical file and the reference in the database you'll have to rename the physical file manually. Something like this should work:

import os

class SomeModel(models.Model):
    file_field = ... 

    def rename(self, new_name):
        old_path = self.file_field.path
        self.file_field.name = new_name

        os.rename(old_path, self.file_field.path)
        self.save()


for m in SomeModel.objects.all():
    new_name = compute_new_filename(m)
    m.rename(new_name)

Note that this is a simplified version and may want to do some handling for the possible IO errors when doing os.rename().

Also this code assumes that you are using the FileSystemStorage and not other custom storage class. In that case, the implementation will need to be adapted to that particular storage mechanism.

Ion Scerbatiuc
  • 1,151
  • 6
  • 10
  • Bah, I was hoping not to have to do this. Thanks. I am looking into using the [`FieldFile`'s save method](https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.fields.files.FieldFile.save), but it may be just as convoluted in the end. Either way, I will probably have to leave it until tomorrow at this point. Thanks, again! – Two-Bit Alchemist Jun 18 '14 at 22:04
  • Using FieldFile's save method is also an option, but it will come with a performance penalty. First you'll have to read the contents of the file in-memory, then save the file with a different name, then delete the old file using `os.unlink`. – Ion Scerbatiuc Jun 18 '14 at 22:11
  • That's ok. This is for a one-off to update the 8000 or so models we already have. The rest can be treated as they come in using the method in the linked question! – Two-Bit Alchemist Jun 19 '14 at 15:01