6

我在 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')

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

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

4

5 回答 5

5

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

m = magic.Magic()
m.from_buffer(request.FILES['my_file_field'].read())

或者使用ifrequest.FILES代替确实不是一种选择。form.cleaned_datadjango.forms.Form

于 2011-12-27T19:46:02.990 回答
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))

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

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

另外

在命名的临时文件仍处于打开状态时,是否可以使用该名称再次打开文件,因平台而异(在 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()

seek(0)此外,您可能想要read()

if hasattr(f, 'seek') and callable(f.seek):
    f.seek(0)

上传数据的存储位置

于 2011-12-27T21:17:39.993 回答
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())

seek(0)此外,您可能想要read()

if hasattr(f, 'seek') and callable(f.seek):
    f.seek(0)

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

于 2014-10-17T06:45:56.143 回答
2

您可以使用django-safe-filefield包来验证上传的文件扩展名是否匹配它的 MIME 类型。

from safe_filefield.forms import SafeFileField

class MyForm(forms.Form):

    attachment = SafeFileField(
        allowed_extensions=('xls', 'xlsx', 'csv')
    )
于 2018-02-07T09:43:29.817 回答
0

如果您正在处理文件上传并且只关心图像, Django 将为content_type您设置(或者更确切地说为自己?):

from django.forms import ModelForm
from django.core.files import File
from django.db import models
class MyPhoto(models.Model):
    photo = models.ImageField(upload_to=photo_upload_to, max_length=1000)
class MyForm(ModelForm):
    class Meta:
        model = MyPhoto
        fields = ['photo']
photo = MyPhoto.objects.first()
photo = File(open('1.jpeg', 'rb'))
form = MyForm(files={'photo': photo})
if form.is_valid():
    print(form.instance.photo.file.content_type)

它不依赖于用户提供的内容类型。但是 django.db.models.fields.files.FieldFile.file无证 财产

实际上,最初content_type是从请求中设置的,但是当表单得到验证时,值会被更新

关于非图像,对我来说做request.FILES['name'].read()似乎没问题。首先,这就是Django所做的。其次,默认情况下大于 2.5 Mb 的文件存储磁盘上。所以让我在这里指出另一个答案。


出于好奇,这是导致更新的堆栈跟踪 content_type

django.forms.forms.BaseForm.is_valid: self.errors
django.forms.forms.BaseForm.errors: self.full_clean()
django.forms.forms.BaseForm.full_clean: self._clean_fields()
django.forms.forms.BaseForm ._clean_fiels: field.clean()
django.forms.fields.FileField.clean: super().clean()
django.forms.fields.Field.clean: self.to_python()
django.forms.fields.ImageField。to_python

于 2019-04-06T19:17:58.273 回答