【问题标题】:Django FileField (or ImageField) open() method returns None for valid file?Django FileField(或ImageField)open()方法为有效文件返回None?
【发布时间】:2012-02-23 21:41:54
【问题描述】:

让我这样说:

模型.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)

【问题讨论】:

    标签: python django


    【解决方案1】:

    因为models.FileField的open方法没有返回任何东西

    你可以使用:

    task.seq_file.read()
    

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

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

    【讨论】:

    • 那么 FileField open() 的目的是什么?
    • 不幸的是,Django 文档目前在这一点上具有误导性:“行为类似于标准 Python open() 方法...” - docs.djangoproject.com/en/1.4/ref/models/fields/… 不,在执行神秘的内部打开操作后返回 None 不是标准 Python 行为。
    • 应该就此提出问题。
    • 哇,这个(读取/seq_file)似乎没有记录在案。非常感谢!
    • 我最近偶然发现了这一点,并在这里提交了一张票和对文档的潜在改进:code.djangoproject.com/ticket/26508
    【解决方案2】:

    FileField 会给你一个类似文件的对象,不需要调用 open() 。在您的示例中,只需调用 task.seq_file.file

    这是为什么呢? FileField 有许多存储后端,其中许多没有磁盘中的文件支持(例如 S3 存储)。我想这就是为什么文档说它返回一个类似文件的对象,而不是一个文件。对于某些类型的存储,“open”方法没有意义。

    【讨论】:

    • 但根据 django 文档,FileField 是一个文件代理,我可以在该对象上调用 open。我什至没有收到关于未定义方法的错误,所以它就在那里,对吧?那么这是一个错误还是我只是不明白什么?
    • @mnowotka:它在那里,但我从未使用过它,FileField 会给你一个类似文件的对象(已经“打开”)。
    • 请记住,FileField 不一定由磁盘上的文件支持(S3,其他类型的云存储)
    • @WenzelJakob:这是一个很好的评论:对于某些类型的存储,“打开”方法没有意义。
    【解决方案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等方法。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-19
        • 2015-01-18
        • 1970-01-01
        • 2011-02-10
        • 2012-05-08
        • 2018-06-01
        • 2013-06-16
        • 1970-01-01
        相关资源
        最近更新 更多