跳转到主要内容

hurry.file是一个高级的Zope 3文件小部件,它尽可能地模仿其他小部件的行为,即使在表单由于验证错误而重新显示时也是如此。它还支持通过Tramline快速进行基于Apache的文件上传和下载。

项目描述

hurry.file字段

文件小部件是在HurryFile对象的基础上构建的

>>> from hurry.file import HurryFile
>>> file = HurryFile('foo.txt', 'mydata')
>>> file.filename
'foo.txt'
>>> file.data
'mydata'
>>> file.size
6
>>> f = file.file
>>> f.read()
'mydata'

HurryFile对象在数据、文件名相匹配的情况下是相等的

>>> file1 = HurryFile('foo.txt', 'mydata')
>>> file2 = HurryFile('foo.txt', 'mydata')
>>> file3 = HurryFile('bar.txt', 'otherdata')
>>> file1 == file2
True
>>> file1 != file2
False
>>> file1 == file3
False
>>> file1 != file3
True

我们也可以从文件对象创建HurryFile对象

>>> from StringIO import StringIO
>>> from zope import component
>>> from hurry.file.interfaces import IFileRetrieval
>>> fileretrieval = component.getUtility(IFileRetrieval)
>>> file = fileretrieval.createFile('bar.txt', StringIO('test data'))
>>> file.filename
'bar.txt'
>>> file.size
9
>>> file.data
'test data'
>>> f = file.file
>>> f.read()
'test data'

这完全相同,但可能更容易使用

>>> from hurry.file import createHurryFile
>>> file = createHurryFile('test2.txt', StringIO('another test file'))
>>> file.filename
'test2.txt'
>>> file.size
17

HurryFile对象通常使用ZODB持久性来存储文件数据。但是,文件也可以通过tramline存储。如果Apache中安装了tramline,则tramline负责生成文件ID并在文件系统中直接存储文件。然后,ID作为文件数据传递,以存储在ZODB中。

首先启用tramline。

tramline目录结构是一个包含两个子目录的目录,一个名为“repository”,另一个名为“upload”

>>> import tempfile, os
>>> dirpath = tempfile.mkdtemp()
>>> repositorypath = os.path.join(dirpath, 'repository')
>>> uploadpath = os.path.join(dirpath, 'upload')
>>> os.mkdir(repositorypath)
>>> os.mkdir(uploadpath)

我们创建一个TramlineFileRetrieval对象,了解这个目录,并将其注册为一个实用工具

>>> from hurry.file.file import TramlineFileRetrievalBase
>>> class TramlineFileRetrieval(TramlineFileRetrievalBase):
...    def getTramlinePath(self):
...        return dirpath
>>> retrieval = TramlineFileRetrieval()
>>> component.provideUtility(retrieval, IFileRetrieval)

现在让我们以 tramline 上传的方式存储文件

>>> f = open(os.path.join(repositorypath, '1'), 'wb')
>>> f.write('test data')
>>> f.close()

将创建一个名为“1”的文件(ZODB中存储的数据将是“1”)

>>> file = HurryFile('foo.txt', '1')

数据现在是“1”,指向实际文件

>>> file.data
'1'

检索文件将返回实际文件

>>> f = file.file
>>> f.read()
'test data'

我们还可以检索其大小

>>> file.size
9L

应该可以创建存储在目录结构中的 Hurry File 对象

>>> file = retrieval.createFile('test.txt', StringIO('my test data'))
>>> file.filename
'test.txt'

现在我们为数据获取一个id

>>> file.data != 'my test data'
True

并且我们可以检索文件本身

>>> f = file.file
>>> f.read()
'my test data'
>>> file.size
12L

现在让我们在我们的实用工具中禁用 tramline

>>> class TramlineFileRetrieval(TramlineFileRetrievalBase):
...     def getTramlinePath(self):
...        return dirpath
...     def isTramlineEnabled(self):
...        return False
>>> component.provideUtility(TramlineFileRetrieval(), IFileRetrieval)

我们期望的行为与 tramline 未安装时相同

>>> file = HurryFile('foo.txt', 'data')
>>> f = file.file
>>> f.read()
'data'
>>> file.size
4

清理

>>> import shutil
>>> shutil.rmtree(dirpath)

hurry.file小部件

这是一个创建文件小部件的基础设施,该小部件尽可能地像 formlib 中的普通文本小部件一样表现。通常,由于表单验证失败的原因,文件小部件会在重新呈现表单时丢失其文件数据。一个小部件保留文件,例如通过将其存储在会话中。

为了做到这一点,我们有一种特殊的方式来存储与文件名一起的文件数据

>>> from hurry.file import HurryFile
>>> some_file = HurryFile('foo.txt', 'the contents')
>>> some_file.filename
'foo.txt'
>>> some_file.data
'the contents'

我们可以提供一个下载小部件。在这种情况下,没有可以下载的内容

>>> from hurry.file.browser import DownloadWidget
>>> from hurry.file.schema import File
>>> from zope.publisher.browser import TestRequest
>>> field = File(__name__='foo', title=u'Foo')
>>> field = field.bind(None)
>>> request = TestRequest()
>>> widget = DownloadWidget(field, request)
>>> widget()
u'<div>Download not available</div>'

即使请求中存在数据,也没有可以下载的内容

>>> from zope.publisher.browser import FileUpload
>>> request = TestRequest(form={'field.foo': FileUpload(some_file)})
>>> widget = DownloadWidget(field, request)
>>> widget()
u'<div>Download not available</div>'

现在设置一个值

>>> widget.setRenderedValue(some_file)
>>> widget()
u'<a href="foo.txt">foo.txt</a>'

现在让我们转到编辑小部件。首先是一个添加表单,没有可用的数据,也没有请求中的数据

>>> from hurry.file.browser import EncodingFileWidget
>>> field = File(__name__='foo', title=u'Foo', required=False)
>>> field = field.bind(None)
>>> request = TestRequest()
>>> widget = EncodingFileWidget(field, request)

>>> def normalize(s):
...   return '\n  '.join(filter(None, s.split(' ')))

>>> print normalize(widget())
<input
  class="fileType"
  id="field.foo"
  name="field.foo"
  size="20"
  type="file"
  />

现在让我们尝试一种情况,其中请求中存在数据,但文件为空字符串

>>> request = TestRequest(form={'field.foo': u''})
>>> widget = EncodingFileWidget(field, request)

>>> def normalize(s):
...   return '\n  '.join(filter(None, s.split(' ')))

>>> print normalize(widget())
<input
  class="fileType"
  id="field.foo"
  name="field.foo"
  size="20"
  type="file"
  />

现在让我们在已有可用数据的情况下再次渲染。应该出现一个包含文件_id的额外隐藏字段

>>> widget.setRenderedValue(some_file)
>>> print normalize(widget())
<input
  class="fileType"
  id="field.foo"
  name="field.foo"
  size="20"
  type="file"
  />
  (foo.txt)<input
  class="hiddenType"
  id="field.foo.file_id"
  name="field.foo.file_id"
  type="hidden"
  value="Zm9vLnR4dAp0aGUgY29udGVudHM="
  />

现在让我们再次渲染,这次请求中提供了文件数据。应该发生相同的事情

>>> request = TestRequest(form={'field.foo': FileUpload(some_file)})
>>> widget = EncodingFileWidget(field, request)
>>> print normalize(widget())
<input
  class="fileType"
  id="field.foo"
  name="field.foo"
  size="20"
  type="file"
  />
  (foo.txt)<input
  class="hiddenType"
  id="field.foo.file_id"
  name="field.foo.file_id"
  type="hidden"
  value="Zm9vLnR4dAp0aGUgY29udGVudHM="
  />

现在让我们再次渲染,这次没有请求中的文件数据,但有一个id。同样,我们应该看到相同的

>>> request = TestRequest(form={'field.foo.file_id':
...                             'Zm9vLnR4dAp0aGUgY29udGVudHM='})
>>> widget = EncodingFileWidget(field, request)
>>> print normalize(widget())
<input
  class="fileType"
  id="field.foo"
  name="field.foo"
  size="20"
  type="file"
  />
  (foo.txt)<input
  class="hiddenType"
  id="field.foo.file_id"
  name="field.foo.file_id"
  type="hidden"
  value="Zm9vLnR4dAp0aGUgY29udGVudHM="
  />

如果有文件数据和id,则会发生其他事情。首先,让我们准备一些新文件

>>> another_file = HurryFile('bar.txt', 'bar contents')

由于编码文件小部件的实现,我们知道文件_id 将是“YmFyLnR4dApiYXIgY29udGVudHM=”。让我们用一个原始id发出一个带有新文件上传的请求

>>> request = TestRequest(form={'field.foo': FileUpload(another_file),
...                             'field.foo.file_id':
...                             'Zm9vLnR4dAp0aGUgY29udGVudHM='})

我们期望新文件是上传的文件

>>> widget = EncodingFileWidget(field, request)
>>> print normalize(widget())
<input
  class="fileType"
  id="field.foo"
  name="field.foo"
  size="20"
  type="file"
  />
  (bar.txt)<input
  class="hiddenType"
  id="field.foo.file_id"
  name="field.foo.file_id"
  type="hidden"
  value="YmFyLnR4dApiYXIgY29udGVudHM="
  />

hurry.file变更

1.2.1 (2011-08-09)

  • 修复HurryFiles中的错误不等式比较。

1.2 (2009-03-11)

  • 添加一个“size”属性,它知道文件的大小(无论是否使用tramline或ZODB存储)

1.1 (2008-08-07)

  • 在buildout.cfg中添加安装测试运行器的配置。

  • 在setup.py中列出依赖项。

  • 依靠zope.session而不是zope.app.session来停止弃用警告。

  • 根据README.txt和file.txt doctests以及CHANGES.txt在setup.py中添加长描述。

1.0 (2006-10-25)

  • 通过IFileRetrieval支持Tramline(快速文件上传/下载)。默认情况下,没有任何变化。

    如果将TramlineFileRetrievalBase的子类注册为IFileRetrieval实用工具,hurry.file将变为Tramline感知。如果手动创建文件,可以通过createHurryFile函数创建,或者通过IFileRetrieval服务的‘createFile’方法创建。这将负责将文件存储在正确位置。

    Tramline可以在以下位置找到:http://codespeak.net/svn/rr/tramline/trunk

0.9.3 (2006-10-23)

  • 在重新显示小部件时返回 tramline_ok 头部,以防我们正在使用 tramline。

0.9.2 (2006-09-28)

  • Zope 3.3在处理文件名编码的方式上有所改变,这破坏了hurry.file。这包括一个解决方案。

0.9.1 (2006-09-22)

  • 第一个cheeseshop发布。

0.9 (2006-06-15)

  • 从hurry包中分离出来,成为hurry.file

  • egg化

0.8 (2006-05-01)

初始公开发布。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源代码分发

hurry.file-1.2.1.tar.gz (15.1 kB 查看散列值)

上传时间 源代码

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面