使用pre_save信号编辑上传的文件(djangos FileField)

时间:2018-05-22 16:09:48

标签: django python-3.x filefield

我想在保存之前在字节级编辑上传的文件(即搜索并删除某个字节序列)。

我按以下方式设置了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)

这首先会导致无限循环。但这可以通过例如减轻只在create或者上调用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 :(得分:0)

第二种解决方案几乎是正确的。文件最终为空(实际上这只发生在更大的文件中)的原因是,有时你必须在打开它之后寻找文件的开头。因此需要更改remove_headers的beginngni:

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