Django 在保存对象之前处理文件上载

Django 在保存对象之前处理文件上载,django,django-models,django-file-upload,Django,Django Models,Django File Upload,我有一个这样的模型: class Talk(BaseModel): title = models.CharField(max_length=200) mp3 = models.FileField(upload_to = u'talks/', max_length=200) seconds = models.IntegerField(blank = True, null = True) def is_mp3(path_to_file):

我有一个这样的模型:

class Talk(BaseModel):
  title        = models.CharField(max_length=200)
  mp3          = models.FileField(upload_to = u'talks/', max_length=200)
  seconds      = models.IntegerField(blank = True, null = True)
def is_mp3(path_to_file):
  from mutagen.mp3 import MP3
  audio = MP3(path_to_file)
  return not audio.info.sketchy
audio = MP3(path_to_file)
self.seconds = audio.info.length
from django.core.exceptions import ValidationError

#this go in your class Model
def clean(self):
    try:
        f = self.mp3.file #the file in Memory
    except ValueError:
        raise ValidationError("A File is needed")
    f.__class__ #this prints <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
    processfile(f)
我想在保存之前验证上传的文件是否是MP3,如下所示:

class Talk(BaseModel):
  title        = models.CharField(max_length=200)
  mp3          = models.FileField(upload_to = u'talks/', max_length=200)
  seconds      = models.IntegerField(blank = True, null = True)
def is_mp3(path_to_file):
  from mutagen.mp3 import MP3
  audio = MP3(path_to_file)
  return not audio.info.sketchy
audio = MP3(path_to_file)
self.seconds = audio.info.length
from django.core.exceptions import ValidationError

#this go in your class Model
def clean(self):
    try:
        f = self.mp3.file #the file in Memory
    except ValueError:
        raise ValidationError("A File is needed")
    f.__class__ #this prints <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
    processfile(f)
一旦我确定我有MP3,我想在秒属性中保存通话长度,如下所示:

class Talk(BaseModel):
  title        = models.CharField(max_length=200)
  mp3          = models.FileField(upload_to = u'talks/', max_length=200)
  seconds      = models.IntegerField(blank = True, null = True)
def is_mp3(path_to_file):
  from mutagen.mp3 import MP3
  audio = MP3(path_to_file)
  return not audio.info.sketchy
audio = MP3(path_to_file)
self.seconds = audio.info.length
from django.core.exceptions import ValidationError

#this go in your class Model
def clean(self):
    try:
        f = self.mp3.file #the file in Memory
    except ValueError:
        raise ValidationError("A File is needed")
    f.__class__ #this prints <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
    processfile(f)
问题是,在保存之前,上传的文件没有路径(请参阅,关闭为
wontfix
),因此我无法处理MP3

我想提出一个很好的验证错误,这样
ModelForm
s就可以显示一个有用的错误(“你这个白痴,你没有上传MP3”之类的)

知道我如何在文件保存之前访问它吗


p、 如果有人知道验证文件的更好方法是MP3,我洗耳恭听-我还希望能够处理ID3数据(设置艺术家、专辑、标题,可能还有专辑艺术,所以我需要它可以处理)。

您可以在视图中访问文件数据


我认为最好的方法是,覆盖表单,从已清理的数据中获取数据,以您喜欢的方式对其进行验证,然后覆盖并使用有关文件的信息填充您的模型实例,然后保存它。

在保存文件之前获取该文件的更干净方法如下:

class Talk(BaseModel):
  title        = models.CharField(max_length=200)
  mp3          = models.FileField(upload_to = u'talks/', max_length=200)
  seconds      = models.IntegerField(blank = True, null = True)
def is_mp3(path_to_file):
  from mutagen.mp3 import MP3
  audio = MP3(path_to_file)
  return not audio.info.sketchy
audio = MP3(path_to_file)
self.seconds = audio.info.length
from django.core.exceptions import ValidationError

#this go in your class Model
def clean(self):
    try:
        f = self.mp3.file #the file in Memory
    except ValueError:
        raise ValidationError("A File is needed")
    f.__class__ #this prints <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
    processfile(f)
来自django.core.exceptions的
导入验证错误
#这是你的课堂模式
def清洁(自清洁):
尝试:
f=self.mp3.file#内存中的文件
除值错误外:
引发ValidationError(“需要一个文件”)
f、 _uuuu类uuuu#这张照片
进程文件(f)

如果我们需要一个路径,答案是

,您可以使用验证文件头然后返回文件开头的技术

class ImageField(FileField):
    # ...    
    def to_python(self, data):
        f = super(ImageField, self).to_python(data)
        # ...
        # We need to get a file object for Pillow. We might have a path or we might
        # have to read the data into memory.
        if hasattr(data, 'temporary_file_path'):
            file = data.temporary_file_path()
        else:
            if hasattr(data, 'read'):
                file = BytesIO(data.read())
            else:
                file = BytesIO(data['content'])

        try:
            # ...
        except Exception:
            # Pillow doesn't recognize it as an image.
            six.reraise(ValidationError, ValidationError(
                self.error_messages['invalid_image'],
                code='invalid_image',
            ), sys.exc_info()[2])
        if hasattr(f, 'seek') and callable(f.seek):
            f.seek(0)
        return f

+1并接受!这似乎是要走的路-似乎有点遗憾,没有一种优雅的方式来使用新的模型验证。也许你可以,但它是相当新的,我还不够熟悉它。