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

发布于 2024-09-01 06:25:44 字数 971 浏览 8 评论 0原文

我有一个这样的模型:

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)

我想在保存之前验证上传的文件是 MP3,如下所示:

def is_mp3(path_to_file):
  from mutagen.mp3 import MP3
  audio = MP3(path_to_file)
  return not audio.info.sketchy

一旦我确定我有 MP3,我想以秒为单位保存演讲的长度属性,如下所示:

audio = MP3(path_to_file)
self.seconds = audio.info.length

问题是,在保存之前,上传的文件没有路径(请参阅 这张票,已关闭为 wontfix),因此我无法处理 MP3。

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

知道如何在保存文件之前访问该文件吗?

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

I've got a model like this:

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)

I want to validate before saving that the uploaded file is an MP3, like this:

def is_mp3(path_to_file):
  from mutagen.mp3 import MP3
  audio = MP3(path_to_file)
  return not audio.info.sketchy

Once I'm sure I've got an MP3, I want to save the length of the talk in the seconds attribute, like this:

audio = MP3(path_to_file)
self.seconds = audio.info.length

The problem is, before saving, the uploaded file doesn't have a path (see this ticket, closed as wontfix), so I can't process the MP3.

I'd like to raise a nice validation error so that ModelForms can display a helpful error ("You idiot, you didn't upload an MP3" or something).

Any idea how I can go about accessing the file before it's saved?

p.s. If anyone knows a better way of validating files are MP3s I'm all ears - I also want to be able to mess around with ID3 data (set the artist, album, title and probably album art, so I need it to be processable by mutagen).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

べ映画 2024-09-08 06:25:44

您可以在 request.FILES 中访问文件数据 在你看来。

我认为最好的方法是将上传的文件绑定到表单,覆盖表单干净的方法,获取UploadedFile 对象 来自 clean_data,以您喜欢的方式验证它,然后覆盖 保存方法 并使用有关文件的信息填充模型实例,然后保存它。

You can access the file data in request.FILES while in your view.

I think that best way is to bind uploaded files to a form, override the forms clean method, get the UploadedFile object from cleaned_data, validate it anyway you like, then override the save method and populate your models instance with information about the file and then save it.

枕头说它不想醒 2024-09-08 06:25:44

在保存之前获取文件的更简洁的方法如下:

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)

如果我们需要路径,答案是 在另一个问题中

a cleaner way to get the file before be saved is like this:

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)

and if we need a path, ther answer is in this other question

云淡月浅 2024-09-08 06:25:44

您可以遵循 ImageField< 使用的技术/code>验证文件头,然后返回到文件的开头。

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

You could follow the technique used by ImageField where it validates the file header and then seeks back to the start of the file.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文