Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How to replace/overwrite/update/change a file of FileField?

In Django, I have the following model:

from django.db import models
from django.core.files.base import File
import os, os.path

class Project(models.Model):
    video = models.FileField(upload_to="media")

    def replace_video(self):
        """Convert video to WebM format."""
        # This is where the conversion takes place,
        # returning a path to the new converted video
        # that I wish to override the old one.
        video_path = convert_video()

        # Replace old video with new one,
        # and remove original unconverted video and original copy of new video.
        self.video.delete(save=True)
        self.video.save(os.path.basename(video_path), File(open(video_path ,"wb")), save=True)
        os.remove(video_path)

I want to be able to replace the file in the FileField video on a model object/instance. The above method I've written does not work. Once I delete the original file, I get the following error:

ValueError: The 'video' attribute has no file associated with it.

How can I replace the file with an updated one, and remove the original one (no more necessary)?

Side-Note: I have found a related issue, but with no satisfying answer.

like image 369
Ory Band Avatar asked Jan 24 '11 21:01

Ory Band


People also ask

How do I save changes in Django model?

save() method can be used to insert new record and update existing record and generally used for saving instance of single record(row in mysql) in database. update() is not used to insert records and can be used to update multiple records(rows in mysql) in database.

What is update in Django?

Update View refers to a view (logic) to update a particular instance of a table from the database with some extra details. It is used to update entries in the database for example, updating an article at geeksforgeeks.


1 Answers

You have two choices.

I'll assume your Project model is only a snippet of code.

Option 1 is to break your model down so that a Project does not have a single file, but rather a Project model is associated with a ProjectFile model. Perhaps one-to-many. One Project as many ProjectFiles. That is, ProjectFile has a ForeigKey to Project.

Then you can add new ProjectFile based on an old ProjectFile. You can delete them, and fool around all you want. Indeed, you can keep both ProjectFile's with an indicator of which is "current".

Option 2 is to self.video.open("w") to open the file for writing. Rewrite the contents "in place". Instead of deleting and replacing the file, rewrite the old file with the new content.

with open(video_path ,"rb") as source:
    self.video.open("wb")
    bytes= source.read(4096)
    if bytes: 
        self.video.write( bytes )
        bytes= source.read(4096)

That will probably do what you want.

Yes, it seems inefficient. It's really not that bad. The conversion takes for ever. The copy takes moments.

like image 196
S.Lott Avatar answered Oct 14 '22 16:10

S.Lott