简体   繁体   English

Django FileField(或ImageField)open()方法为有效文件返回None?

[英]Django FileField (or ImageField) open() method returns None for valid file?

let me put it like this:让我这样说:

model.py:模型.py:

class Task(models.Model):
    ...
    seq_file = models.FileField(upload_to='files/', blank=True, null=True)
    ...

ajax.py (I'm using dajaxice but it doesn't matter): ajax.py(我正在使用 dajaxice 但没关系):

...
def startTask(request, name):
    task = Task.objects.get(task_name=name)
    data = task.seq_file.open()
    filename = os.path.join(settings.MEDIA_ROOT ,task.seq_file.name)
    if not os.path.isfile(filename):
        raise Exception, "file " + filename + " not found."
    sequences = parser.parse(data.read())
    ...

this returns:这将返回:

File "/home/mnowotka/Dokumenty/MgrFuncAdnot/app/django-gui/src/gui/ajax.py", line 43, in startTask
sequences = parser.parse(data.read())

AttributeError: 'NoneType' object has no attribute 'read'

but:但:

...
def startTask(request, name):
    task = Task.objects.get(task_name=name)
    filename = os.path.join(settings.MEDIA_ROOT ,task.seq_file.name)
    if not os.path.isfile(filename):
        raise Exception, "file " + filename + " not found."
    data = open(filename)  
    sequences = parser.parse(data.read())
    ...

works perfectly!完美运行! Why?为什么?

(I'm using django 1.3) (我正在使用 Django 1.3)

because open method of models.FileField doesn't return anything因为models.FileField的open方法不返回任何东西

you can just use:你可以使用:

task.seq_file.read()

and you don't need calculate path of file for checking if file exist.并且您不需要计算文件路径来检查文件是否存在。 you can use task.seq_file.path:您可以使用 task.seq_file.path:

if not os.path.isfile(task.seq_file.path):
    ....

A FileField will give you a file-like object and there is no need to call open() on it. FileField将为您提供一个类似文件的对象,并且无需对其调用 open() 。 In your example, just call task.seq_file.file .在您的示例中,只需调用task.seq_file.file

Why is that?这是为什么? There are many storage backends for FileField , and many of them are not backed by a file in disk (think of S3 storage, for example). FileField有许多存储后端,其中许多后端都没有磁盘中的文件支持(例如,想想 S3 存储)。 I guess that is why the documentation says it returns a file-like object, not a file.我想这就是为什么文档说它返回一个类似文件的对象,而不是一个文件。 For some kinds of storage the "open" method makes no sense.对于某些类型的存储,“打开”方法没有意义。

When in doubt, check the code.如有疑问,请检查代码。 Here's an excerpt from django.db.models.fields.files :这是django.db.models.fields.files的摘录:

def open(self, mode='rb'):
    self._require_file()
    self.file.open(mode)
# open() doesn't alter the file's contents, but it does reset the pointer
open.alters_data = True

So, in the case of a FileField , open reopens the file using the specified mode.因此,在FileField的情况下, open使用指定的模式重新打开文件。 Then, once you call open , you can continue to use methods like read using the newly applied mode.然后,一旦您调用open ,您就可以使用新应用的模式继续使用read方法。

Surprisingly but django.db.models.fields.files does not utilize file.storage.exists() method so I had to implement my own small function to have cross-storage compatible check for actual physical file existence:令人惊讶的是,但django.db.models.fields.files不使用file.storage.exists()方法,所以我必须实现我自己的小函数来进行跨存储兼容检查实际物理文件的存在:

# Check whether actual file of FileField exists (is not deleted / moved out).
def file_exists(obj):
    return obj.storage.exists(obj.name)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM