[我为这个问题的篇幅提前道歉。]
我在Debian squeeze上使用Django 1.2.3-3 + squeeze1。
我正在编写一个将zip文件上传到磁盘的应用程序
临时位置,解压缩它们,然后将结果保存到
永久的位置。解压缩的文件作为名为的类在数据库中注册
解压后FileUpload
。上传的压缩文件也对应一个类,
但出于这个问题的目的,我会忽略它。 FileUpload
看起来像这样。
class FileUpload(models.Model):
folder = models.ForeignKey(FolderUpload, null=True, blank=True, related_name='parentfolder')
upload_date = models.DateTimeField(default=datetime.now(), blank=True, editable=False)
upload = models.FileField(upload_to=file_upload_path)
name = models.CharField(max_length=100)
description = models.CharField(blank=True, max_length=200)
def save(self):
if not self.id:
if self.folder == None:
pass
else:
self.path = self.folder.path
super(FileUpload, self).save()
我也在使用
定义的表单from django.forms import ChoiceField, Form, ModelForm
class FileUploadForm(ModelForm):
class Meta:
model = FileUpload
获取磁盘上解压缩文件的功能。注册他们
与数据库,并将它们移动到正确的位置被调用
addFile
。我之前使用过这个:
def addFile(name, filename, description, content, folder_id=None):
#f = open(filename, 'r')
#content = f.read()
from forms import FileUploadForm
from django.core.files.uploadedfile import SimpleUploadedFile
if folder_id == None:
data = {'name':name, 'description':description}
else:
data = {'name':name, 'description':description, 'folder':str(folder_id)}
file_data = {'upload': SimpleUploadedFile(filename, content)}
ff = FileUploadForm(data, file_data)
try:
zf = ff.save(commit=False)
zf.save()
except:
raise RuntimeError, "Form error is %s."%(ff.errors)
return zf
这很有用,但问题是它将整个文件转储到了 记忆。对于大文件,特别是Python不知道 这是记忆经济,这消耗了大量的内存。所以我 切换到这个:
from django.core.files.uploadedfile import UploadedFile
class UnzippedFile(UploadedFile):
def __init__(self, file, filepath, content_type='text/plain', charset=None):
import os
self.filepath = filepath
self.name = os.path.basename(filepath)
self.size = os.path.getsize(filepath)
self.content_type = content_type
self.charset = charset
super(UnzippedFile, self).__init__(file, self.name, content_type, self.size, charset)
def temporary_file_path(self):
"""
Returns the full path of this file.
"""
return self.filepath
def addFile(filepath, description, file, folder_id=None):
import os, sys
from forms import FileUploadForm
from django.core.files.uploadedfile import UploadedFile
name = os.path.basename(filepath)
if folder_id == None:
data = {'name':name, 'description':description}
else:
data = {'name':name, 'description':description, 'folder':str(folder_id)}
file_data = {'upload': UnzippedFile(file, filepath)}
ff = FileUploadForm(data, file_data)
try:
zf = ff.save(commit=False)
zf.save()
except:
raise
return zf
我被迫继承UploadedFile
,因为没有派生
已经在那里的课程(在
django/core/files/uploadedfile.py
)似乎做了我想做的事。
temporary_file_path
函数在那里,因为Django File Uploads docs说
UploadedFile.temporary_file_path()
只有上传到磁盘上的文件才会有此方法;它返回 临时上传文件的完整路径。
FileSystemStorage
类似乎在查找此属性
_save
功能如后所述。
如果n
是zip存档中文件的相对路径,那么
用法是
name = os.path.normpath(os.path.basename(n)) # name of file
pathname = os.path.join(dirname, n) # full file path
description = "from zip file '" + zipfilename + "'" # `zipfilename` is the name of the zip file
fname = open(pathname) # file handle
f = addFile(pathname, description, fname)
这是有效的,但我通过代码进行了跟踪,发现代码是
使用流式传输,在这种情况下显然是最佳选择
就是将文件从临时位置复制到
永久的位置。有问题的代码在
django/core/files/storage.py
,在_save
函数中
FileSystemStorage
课程。在_save
中,name
是相对路径
目的地,content
是File
对象。
def _save(self, name, content):
full_path = self.path(name)
directory = os.path.dirname(full_path)
[...]
while True:
try:
# This file has a file path that we can move.
if hasattr(content, 'temporary_file_path'):
file_move_safe(content.temporary_file_path(), full_path)
content.close()
# This is a normal uploadedfile that we can stream.
else:
# This fun binary flag incantation makes os.open throw an
# OSError if the file already exists before we open it.
fd = os.open(full_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0))
try:
locks.lock(fd, locks.LOCK_EX)
for chunk in content.chunks():
os.write(fd, chunk)
finally:
locks.unlock(fd)
os.close(fd)
except OSError, e:
if e.errno == errno.EEXIST:
# Ooops, the file exists. We need a new file name.
name = self.get_available_name(name)
full_path = self.path(name)
else:
raise
else:
# OK, the file save worked. Break out of the loop.
break
_save
函数正在查找属性
temporary_file_path
。我相信这个代码是打算触发的
通过前面提到的temporary_file_path
函数
django/core/files/uploadedfile.py
。但是,那个类就是
实际传递(对应于content
参数)是<class
'django.db.models.fields.files.FieldFile'>
,这是什么的
此对象的属性dict(content.__dict__
)如下所示:
{'_committed': False, 'name': u'foo', 'instance': <FileUpload: foo>,
'_file': <UnzippedFile: foo (text/plain)>, 'storage':<django.core.files.storage.DefaultStorage object at 0x9a70ccc>,
'field': <django.db.models.fields.files.FileField object at0x9ce9b4c>, 'mode': None}
temporary_file_path
附在。{
UnzippedFile
类,位于_file
数据成员中。所以
content._file
有一个temporary_file_path
属性,而不是content
本身。
这是常规文件上传的样子。如你所见,它是相似的。
[Fri Jun 17 08:05:33 2011] [error] type of content is <class 'django.db.models.fields.files.FieldFile'>
[Fri Jun 17 08:05:33 2011] [error] {'_committed': False, 'name': u'behavior.py',
'instance': <FileUpload: b>, '_file': <TemporaryUploadedFile: behavior.py (text/x-python)>,
'storage': <django.core.files.storage.DefaultStorage object at 0xb8d7fd8c>,
'field': <django.db.models.fields.files.FileField object at 0xb8eb584c>, 'mode': None}
我很难详细了解代码的来源
FileUploadForm
save
到Storage
对象。 Django表格
特别是代码非常模糊。
无论如何,我的问题是,在所有这些设置之后,第一个是何时/何时
下面的选项,file_move_safe
应该被激活?我
看到这里不匹配。这是一个错误吗?任何人都可以澄清吗?
答案 0 :(得分:0)
if hasattr(content, 'temporary_file_path')
由于您声明内容没有temporary_file_path标识符,因此上述条件永远不会与此条件相等。但是,由于content._file可以使用以下内容来获取您正在寻找的功能
if hasattr(content, '_file'):
if hasattr(content._file,'temporary_file_path'):