djangodjango-modelsdjango-formsmoviepydjango-file-upload

How do I convert a file to mp3 before saving django?


I found some information on extending and changing the save() method on my model, but a few other people mentioned that it was bad practice to do that, and one should instead modify the admin form.

Extracting the audio from a mp4 is easy using moviepy, I just need to run these lines:

from moviepy.editor import *

audio = VideoFileClip("test-file.mp4").audio
audio.write_audiofile("audio.mp3")

However, I do not know where to put this within my model to ensure it gets run and saves the correct file.

My model looks like this:

Class MyModel(models.Model):
    audio = models.FileField(upload_to=update_filename)

It's important this code is executed before the file gets saved, and the audio file is the one getting saved to the audio attribute of my model.


Solution

  • Instead of changing the save method, I needed to change the clean method, which is where the data for a model is validated and where one can modify the attributes of a model.

    from django.db import models
    from django.core.exceptions import ValidationError
    from moviepy.editor import *
    
    class MyModel(models.Model):
        audio = models.FileField(upload_to=lambda i, f: f[0:-4] + ".mp3")
    
        def clean(self):
            super().clean()
            extension = self.audio.name[len(self.audio.name) - 4:]
            file = self.audio.file
            file.__class__
            if extension != ".mp3" and extension != ".mp4":
                raise ValidationError("Incorrect File Format Uploaded. Valid Formats: (MP3, MP4)")
            elif extension == ".mp4":
                file_audio = VideoFileClip(file.temporary_file_path()).audio
                new_file_path = file.temporary_file_path()[:-4] + ".mp3"
                file_audio.write_audiofile(new_file_path)
                file.file.name = new_file_path
    

    It's important to run super.clean() before modifying a model's attributes, because if one runs it after modifying an attribute, it will return a ValidationError.