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

时间:2012-02-23 21:41:54

标签: python django

让我这样说:

model.py:

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

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())
    ...

返回:

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'

但:

...
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())
    ...

完美无缺! 为什么呢?

(我正在使用django 1.3)

4 个答案:

答案 0 :(得分:29)

因为模型的open方法.FileField不返回任何内容

你可以使用:

task.seq_file.read()

并且您不需要计算文件的路径来检查文件是否存在。你可以使用task.seq_file.path:

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

答案 1 :(得分:7)

FileField将为您提供类似文件的对象,而无需在其上调用open()。在您的示例中,只需致电task.seq_file.file

为什么? FileField有许多存储后端,其中许多不受磁盘中文件的支持(例如,考虑S3存储)。我猜这就是文档说它返回类似文件的对象而不是文件的原因。对于某些类型的存储,“开放”方法毫无意义。

答案 2 :(得分:3)

如有疑问,请检查代码。以下是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

因此,在FileField的情况下,open使用指定的模式重新打开文件。然后,在您拨打open后,您可以继续使用新应用模式的read等方法。

答案 3 :(得分:0)

令人惊讶的是,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)