Редактировать загруженный файл (djangos FileField), используя сигнал pre_save - PullRequest
0 голосов
/ 22 мая 2018

Я хочу отредактировать загруженный файл на уровне байтов (т.е. искать и удалять определенную последовательность байтов) перед его сохранением.

У меня есть сигнал pre_save, настроенный следующим образом:

class Snippet(models.Model):
    name = models.CharField(max_length=256, unique=True)
    audio_file = models.FileField(upload_to=generate_file_name, blank=True, null=True)

@receiver(models.signals.pre_save, sender=Snippet)
def prepare_save(sender, instance, **kwargs):
    if instance.audio_file:
        remove_headers(instance)

Теперь у меня возникли проблемы с реализацией функции remove_headers таким образом, что я могу редактировать файл, пока он еще находится в памяти, и впоследствии сохранить его.Я пробовал среди прочего следующее:

def remove_headers(instance):
    byte_sequence = b'bytestoremove'
    f = instance.audio_file.read()
    file_in_hex = f.hex()
    file_in_hex = re.sub(byte_sequence.hex(), '', file_in_hex)

    x = b''
    x = x.fromhex(file_in_hex)

    tmp_file = TemporaryFile()
    tmp_file.write(x)
    tmp_file.flush()
    tmp_file.seek(0)
    instance.audio_file.save(instance.audio_file.name, tmp_file, save=True)

Это прежде всего приведет к бесконечному циклу.Но это может быть смягчено, например, только путем вызова метода remove_headers при создании или около того.Однако это не сработало, файл не изменился.Я также попытался заменить последнюю строку на:

instance.audio_file = File(tmp_file, name=instance.audio_file.name)

Однако это привело к записи / сохранению пустого файла.Любопытно, что при написании теста этот метод работает:

def test_header_removed(self):
    snippet = mommy.make(Snippet)
    snippet.audio_file.save('newname.mp3', ContentFile('contentbytestoremovecontent'))
    snippet.save()
    self.assertEqual(snippet.audio_file.read(), b'contentcontent')

Этот тест не завершается неудачей, несмотря на то, что файл в конце равен нулю байтов.Что мне здесь не хватает?

1 Ответ

0 голосов
/ 25 мая 2018

Второе решение было почти правильным.Причина, по которой файлы оказались пустыми (на самом деле это произошло только с большими файлами), заключалась в том, что иногда вам приходится искать начало файла после его открытия.Таким образом, начало remove_headers должно быть изменено:

def remove_headers(instance):
    byte_sequence = b'bytestoremove'
    instance.audio_file.seek(0)
    f = instance.audio_file.read()
    file_in_hex = f.hex()
...