且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

上传文件后保存更新FileField文件(Django)

更新时间:2023-02-23 21:13:28

没有魔术和简单的方法来做到这一点。从数据库(for循环)加载对象时,由视频属性引用的文件的名称也从数据库加载。您不能只是更改它,并使底层文件更改它的名称。



为了完成物理文件和数据库中的引用的名称更改,必须手动重命名物理文件。这样做应该可以工作:

  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()


在SomeModel.objects.all()中:
new_name = compute_new_filename(m)
m.rename(new_name)

请注意,一个简化的版本,并且可能希望在执行 os.rename()时对可能的IO错误进行一些处理。



此代码假定您正在使用FileSystemStorage而不是其他自定义存储类。在这种情况下,实施将需要适应该特定的存储机制。


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?

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.