使用 pre_save 信号编辑上传的文件 (djangos FileField)
Edit uploaded file (djangos FileField) using pre_save signal
我想在保存之前在字节级别编辑上传的文件(即搜索和删除某个字节序列)。
我按以下方式设置了 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)
然而,这导致一个空文件 written/saved。
奇怪的是在写测试的时候,这个方法好像管用:
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')
这个测试没有失败,尽管文件最后是零字节。
我在这里错过了什么?
第二种解法基本正确。文件最终为空的原因(实际上这只发生在较大的文件上)是,有时您必须在打开文件后寻找文件的开头。所以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()
我想在保存之前在字节级别编辑上传的文件(即搜索和删除某个字节序列)。
我按以下方式设置了 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)
然而,这导致一个空文件 written/saved。 奇怪的是在写测试的时候,这个方法好像管用:
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')
这个测试没有失败,尽管文件最后是零字节。 我在这里错过了什么?
第二种解法基本正确。文件最终为空的原因(实际上这只发生在较大的文件上)是,有时您必须在打开文件后寻找文件的开头。所以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()