如何使用魔术来验证Django表单清洁方法中的文件类型?

dan*_*007 5 django django-forms django-file-upload python-magic

我已经在Django中使用FileField编写了一个电子邮件表单类。我想通过检查其mimetype来检查上传文件的类型。随后,我想将文件类型限制为pdf,word和开放式Office文档。

为此,我已经安装了python-magic,并希望按照python-magic的规范检查文件类型,如下所示:

mime = magic.Magic(mime=True)
file_mime_type = mime.from_file('address/of/file.txt')
Run Code Online (Sandbox Code Playgroud)

但是,最近上传的文件在我的服务器上缺少地址。我还不知道任何类似于“ from_file_content”的mime对象的方法,该方法可以检查给定文件内容的mime类型。

使用魔术验证Django表单中上传文件的文件类型的有效方法是什么?

Sta*_*tan 5

为什么不尝试在你看来这样的事情:

m = magic.Magic()
m.from_buffer(request.FILES['my_file_field'].read())
Run Code Online (Sandbox Code Playgroud)

或者request.FILES代替form.cleaned_dataifdjango.forms.Form真的不是一个选择。


Ale*_*ich 5

Stan描述了带有缓冲的良好变体。不幸的是,这种方法的缺点是将文件读取到内存中。另一种选择是使用临时存储的文件:

import tempfile
import magic
with tempfile.NamedTemporaryFile() as tmp:
    for chunk in form.cleaned_data['file'].chunks():
        tmp.write(chunk)
    print(magic.from_file(tmp.name, mime=True))
Run Code Online (Sandbox Code Playgroud)

另外,您可能要检查文件大小:

if form.cleaned_data['file'].size < ...:
    print(magic.from_buffer(form.cleaned_data['file'].read()))
else:
    # store to disk (the code above)
Run Code Online (Sandbox Code Playgroud)

另外

在命名的临时文件仍处于打开状态时,是否可以使用该名称第二次打开文件,会因平台而异(可以在Unix上使用;在Windows NT或更高版本上不能使用)。

所以,你可能要处理它像这样

import os
tmp = tempfile.NamedTemporaryFile(delete=False)
try:
    for chunk in form.cleaned_data['file'].chunks():
        tmp.write(chunk)
    print(magic.from_file(tmp.name, mime=True))
finally:
    os.unlink(tmp.name)
    tmp.close()
Run Code Online (Sandbox Code Playgroud)

此外,你可能想seek(0)read()

if hasattr(f, 'seek') and callable(f.seek):
    f.seek(0)
Run Code Online (Sandbox Code Playgroud)

上载数据的存储位置

  • @AlexeySavanovich:在这种情况下,`m.from_buffer(request.FILES ['my_file_field']。multiple_chunks())`应该可以工作。 (2认同)

Omi*_*aha 5

mime = magic.Magic(mime=True)

attachment = form.cleaned_data['attachment']

if hasattr(attachment, 'temporary_file_path'):
    # file is temporary on the disk, so we can get full path of it.
    mime_type = mime.from_file(attachment.temporary_file_path())
else:
    # file is on the memory
    mime_type = mime.from_buffer(attachment.read())
Run Code Online (Sandbox Code Playgroud)

另外,您可能想seek(0)在之后read()

if hasattr(f, 'seek') and callable(f.seek):
    f.seek(0)
Run Code Online (Sandbox Code Playgroud)

Django 代码示例。在验证期间对图像字段执行。