在表单的clean方法中读取文件数据

16

所以,我正在实现对我的先前问题的答案。

这是我的模型:

class Talk(models.Model):
  title        = models.CharField(max_length=200)
  mp3          = models.FileField(upload_to = u'talks/', max_length=200)

这是我的表单:

class TalkForm(forms.ModelForm):
  def clean(self):
    super(TalkForm, self).clean()
    cleaned_data = self.cleaned_data

    if u'mp3' in self.files:
      from mutagen.mp3 import MP3
      if hasattr(self.files['mp3'], 'temporary_file_path'):
        audio = MP3(self.files['mp3'].temporary_file_path())
      else:
        # What goes here?
        audio = None # setting to None for now
      ...
    return cleaned_data

  class Meta:
    model = Talk

Mutagen需要文件类对象或者在磁盘上的文件名(我认为)- 第一种情况(上传的文件大于内存中可处理的文件大小)可以正常工作,但是我不知道如何处理InMemoryUploadedFile得到的其他情况。我尝试过:

# TypeError (coercing to Unicode: need string or buffer, InMemoryUploadedFile found)
audio = MP3(self.files['mp3'])

# TypeError (coercing to Unicode: need string or buffer, cStringIO.StringO found)
audio = MP3(self.files['mp3'].file)

# Hangs seemingly indefinitely on my test file (~800KB)
audio = MP3(self.files['mp3'].file.read())

mutagen是否有问题,还是我的操作有误?

在rebus的回答之后

在我的ModelAdmin类中像这样实时修改FILE_UPLOAD_HANDLERS设置:

def add_view(self, request, form_url='', extra_context=None):
  request.upload_handlers = [TemporaryFileUploadHandler()]
  return super(TalkAdmin, self).add_view(request, form_url, extra_context)

当我点击提交按钮时,出现了500错误:

在上传处理完成后,您无法设置上传处理程序。

尽管我尽可能早地设置了它!

此外,我不确定我是否在返回的对象中有一个save方法(我已经查看了dir(self.files['mp3'].file)dir(self.files['mp3']))。

1个回答

30
你可以尝试更改FILE_UPLOAD_HANDLERS,以便 Django 始终使用临时文件处理程序: FILE_UPLOAD_HANDLERS 默认值:
("django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler",)

你可以通过在settings.py中覆盖设置,仅使用TemporaryFileUploadHandler

编辑:

更简单的方法,一开始就应该考虑这个:(:

from your.models import Talk
mp3 = self.files['mp3']
f = Talk.mp3.save('somename.mp3', mp3)
MP3(f.mp3.path)
>>> {'TRCK': TRCK(encoding=0, text=[u'5'])}

你可以通过以下方式将InMemoryUploadedFile保存到磁盘,然后使用该文件的路径来处理mutagen

编辑:

同样的事情,没有模型实例。

import os

from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.conf import settings

from mutagen.mp3 import MP3

mp3 = request.FILES['mp3'] # or self.files['mp3'] in your form

path = default_storage.save('tmp/somename.mp3', ContentFile(mp3.read()))
MP3(os.path.join(settings.MEDIA_ROOT, path))

注意它正在将文件保存在MEDIA_ROOT中,当我尝试将其保存到其他任何地方时,会出现SuspiciousOperation错误,因为您可以写入的位置是有限制的...我想你应该在检查完文件后删除它,真正的东西将在您的模型上...

path = default_storage.delete('tmp/somename.mp3')

实际上,您可以在模型的ModelAdmin定义中对这两个视图进行子类化。http://docs.djangoproject.com/en/dev/ref/contrib/admin/#other-methods - Davor Lucic
@rebus - 感谢您的帮助,但是没有运气 - 请看我的编辑。还有其他的想法吗? - Dominic Rodger
@Dominic Rodger 我稍微编辑了一个答案,这样做应该会简单得多,结果发现要绕过围绕着管理员视图的csrf保护(它访问request.POST)来更改upload_handlers并不是很容易。 - Davor Lucic
@rebus - 你修改后的解决方案行不通(除非通过Talk的实例才能访问Talk.mp3)- 我刚刚关闭了MemoryFileUploadHandler - 为了我的理智着想,我会承担较小文件上传的影响。 - Dominic Rodger
@rebus - 我已经在这个问题上设置了悬赏,一旦我被允许感谢你的所有帮助,我就会授予你奖励。今晚稍后我会尝试default_storage的东西,但如果不起作用,我很乐意关闭MemoryFileUploadhandler。再次感谢! - Dominic Rodger
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接