Как использовать post_save и использовать instance.save внутри post_save без повторного вызова post_save? - PullRequest
0 голосов
/ 04 апреля 2020

Я использую сигнал для изменения загруженного файла и выполняю некоторый процесс для преобразования файла .mkv | mp4 в файлы .m3u8 и .ts, но когда я сохраняю экземпляр, используя новый файл .m3u8, созданный в сигнале, метод instance.save вызывает сигнал снова, и это вызывает ошибку.

Пример кода:

@receiver(post_save, sender=Lecture)
def handle_video_upload(sender, instance, created, **kwargs):
    # check if a new video has uploaded
    file_has_changed = instance.tracker.has_changed('file')

    if created or file_has_changed and instance.file_type == "V":
    # .../ process to convert video into a .m3u8 file...

        # open the m3u8 created file and change the original (mp4, mkv...) file for the m3u8
        with open(m3u8_absolute_path, "r") as file_object:
            file_m3u8 = File(name=m3u8_absolute_path, file=file_object)
            instance.file.save(m3u8_filename, file_m3u8) # this call this signal again and raise a error

поле файла: file = models.FileField()

Полный код :

import subprocess
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.files import File
from pathlib import Path
from .models import Lecture


@receiver(post_save, sender=Lecture)
def handle_video_upload(sender, instance, created, **kwargs):
    # check if the file field has changed
    file_has_changed = instance.tracker.has_changed('file')

    # the process run when:
    # the file_type is a video (setted as "V"), and:
    # - the instance is created
    # - the video is changed (i.e, reuploaded)
    if created or file_has_changed and instance.file_type == "V":
        instance_absolute_path = Path(instance.file.path)
        m3u8_absolute_path = instance_absolute_path.with_suffix(".m3u8")
        m3u8_filename = m3u8_absolute_path.name

        # use shell commands to create HLS .m3u8 file
        # and delete the original video file
        subprocess.run([
            "ffmpeg",
            "-i",
            instance_absolute_path,
            "-f",
            "hls",
            m3u8_absolute_path
        ])
        subprocess.run(["rm", instance_absolute_path])

        # update the file with the new .m3u8 file
        with open(m3u8_absolute_path, "r") as file_object:
            file_m3u8 = File(name=m3u8_absolute_path, file=file_object)
            instance.file.save(m3u8_filename, file_m3u8)

соответствующий код модели:

class Lecture(models.Model):
    FILE_TYPE_CHOICES = (("V", "Video"), ("P", "PDF"))
    file = models.FileField()
    file_type = models.CharField(
        max_length=1,
        choices=FILE_TYPE_CHOICES,
        default="V")
    tracker = FieldTracker()

Ошибка на сайте:

FileNotFoundError at /admin/lectures/lecture/add/
[Errno 2] No such file or directory: '/home/marcos/geeknoon/geeknoon_server/local/media/media/lectures/second/2020-04-04_16-11-20_8bbOfdb.m3u8

Traceback: https://pastebin.com/PQxgv78n

...