跳转到主要内容

图像、文件和带有文件名的blob文件类型和字段

项目描述

简介

此包包含用于存储的字段和包装对象:

  • 带有文件名的文件

  • 带有文件名的图像

提供了基于Blob和非基于Blob的类型。基于Blob的类型需要ZODB3包的版本为3.8.1或更高版本,并在zope.conf中配置BLOB。

注册了plone.supermodel处理器。

有关更多详细信息,请参阅usage.rst doctest。

源代码

注意:此包根据BSD许可证授权。请勿添加对GPL代码的依赖!

贡献者请阅读文档Plone核心开发的流程

源代码位于托管在GitHub上的Plone代码仓库

变更日志

6.3.1 (2024-07-30)

错误修复

  • 修复:上传未设置宽度和高度的svg @dobri1408 (#161)

6.3.0 (2024-03-15)

新功能

  • 改进对未注册但常见的类型的内容类型检测逻辑。

    更改get_contenttype以支持未注册或未注册的IANA的常见类型,如image/webp或audio/midi。

    注意:image/webp已经是一个IANA注册的类型,并且也已由Products.MimetypesRegistry添加。[thet] (157-2)

  • 支持允许的媒体类型。

    支持将文件限制为特定媒体类型,通过在文件和图像字段上设置“accept”属性,就像HTML文件输入的“accept”属性一样。

    修复:#157 [thet] (#157)

6.2.3 (2023-11-03)

错误修复

  • 在检查mimetype是否允许内联显示时更加严格。[maurits] (#1167)

6.2.2 (2023-10-18)

错误修复

  • 修复文件修改时间的计算。@davisagli (#153)

6.2.1 (2023-09-21)

错误修复

  • 修复存储的XSS(跨站脚本)问题,针对SVG图像。通过强制下载而不是内联显示来解决。请参阅安全公告。[maurits] (#1)

6.2.0 (2023-09-14)

新功能

  • 添加内部修改时间戳,并提供对_p_mtime的回退。[mathias.leimgruber] (#149)

  • 将新的内部修改时间戳用作缩放哈希键的一部分。[mathias.leimgruber] (#150)

6.1.2 (2023-08-31)

错误修复

  • 修复了包含大量元数据的SVG图像无法正确显示的问题(导致宽度和高度为1px)。当标签超过MAX_INFO_BYTES限制时,可能会出现此问题。

    修复了问题问题147。[mliebischer] (#147)

6.1.1 (2023-06-22)

错误修复

  • 如果发布时不包含子路径,则返回400 Bad Request响应。@@images视图。[davisagli] (#144)

测试

  • 修复测试以与各种beautifulsoup4版本一起工作。[maurits] (#867)

6.1.0 (2023-05-22)

新功能

  • Zope2FileUploadStorable代码从plone.app.z3cform移动到这里,以解决循环依赖。[gforcada] (#3764)

6.0.2 (2023-05-08)

错误修复

  • 修复使用原始图像而不是缩放时的图片标签。[maurits] (#142)

6.0.1 (2023-03-14)

测试

  • Tox:显式测试plone.namedfile包。[maurits] (#50)

6.0.0 (2022-11-22)

错误修复

  • 当找不到图片变体的缩放比例时记录警告。直到现在,这会导致异常。[maurits] (#134)

  • 防止匿名用户首次加载包含私有图片的页面时抛出异常。匿名用户在加载图片时仍然会收到未授权访问,这是预期的。HTML至少可以正常显示。修复了问题135。[maurits] (#135)

  • 修复了每次请求原始图片时都写入数据库的问题。这发生在请求具有唯一ID的原始图片时。[maurits] (#3678)

6.0.0b5 (2022-10-03)

破坏性更改

  • 不再在3.6上测试Plone 5.2,在3.7上测试Plone 6.0。[maurits] (#3637)

错误修复

  • 使用mode参数代替已废弃的direction,并向用户发出警告。[petschki, maurits] (#102)

6.0.0b4 (2022-09-07)

错误修复

  • getAllowedSizesgetQuality从CMFPlone.utils移动到本包。[jensens] (#132)

6.0.0b3 (2022-07-20)

错误修复

  • 从ImageScale类获取标题。当上下文是瓦片时,防止跟踪异常。如果没有找到标题,则回退到空字符串。[maurits] (#128)

6.0.0b2 (2022-06-27)

错误修复

  • 不要在image_scales字典中使用完整URL。[petschki] (#123)

6.0.0b1 (2022-06-23)

新功能

  • 创建标签不再生成实际的缩放。[maurits] (#113)

  • 将图片方法添加到ImageScaling中,并将其包含在@@image-test中。图片标签仅在Plone 6上工作,其他几个分支合并了图片变体。请参阅plip-image-srcsets.cfg。如果不可用(如Plone 5.2),则创建一个普通的图片标签。[MrTango] (#113)

  • 为编辑器添加@@images-test页面。这显示当前上下文图片字段的多个变体。它显示存储的缩放列表。它允许清除存储的缩放。[maurits] (#113)

  • 移除标记请求禁用CSRF保护(需要plone.scale与https://github.com/plone/plone.scale/pull/58)[mamico] (#177)

  • 正确使用属性_sizes进行本地缓存,确保可用_sizes [mamico] (#177)

  • 仅在缺失时向缩放存储添加额外信息 [mamico] (#177)

  • 将图像字段适配器注册到新的image_scales元数据。在图像缩放视图中使用此适配器从脑图列表中获取图像。此代码在Plone 5上不活动,仅在Plone 6上。[cekk, maurits] (#3521)

错误修复

  • 清理:isort,black,pyupgrade,移除six的使用等。[maurits] (#120)

6.0.0a4 (2022-05-26)

错误修复

  • 仅检查宽度以确定HiDPI图像是否会比原始图像大。否则,当缩放定义的高度为65536时,永远不会包含HiDPI srcsets。[maurits] (#114)

  • 修复了即使作为管理员访问私有图片的@@images/image时的未授权访问问题。修复了先前版本中引入的问题。[maurits] (#118)

6.0.0a3 (2022-02-28)

错误修复

  • ImageScaling视图:使用guarded_orig_image从URL获取字段。这主要使得视图更容易自定义。[maurits] (#104)

6.0.0a2 (2022-02-23)

破坏性更改

  • 从setup.py中删除了已废弃的额外功能。这些功能现在已删除:blobseditormarshalerscalessupermodel。请参阅问题106。[maurits] (#106)

新功能

  • AnnotationStorage注册为IImageScaleStorage多适配器。两者均来自plone.scale。在我们存储或获取图像缩放时使用此适配器。[maurits] (#44)

6.0.0a1 (2022-01-28)

破坏性更改

  • 停止对Python 2.7的支持。主要目标是Plone 6,但我们尝试使其在Plone 5.2上运行,使用Python 3。请参阅plone.scale问题44中的讨论。[maurits] (#44)

错误修复

  • 修复Python 3上的NameError file。使用io.IOBase代替。(#3)

5.6.0 (2021-12-29)

新功能

  • 使DefaultImageScalingFactory更灵活,具有您可以重写的函数。[maurits] (#104)

5.5.1 (2021-07-28)

错误修复

  • 强烈缓存稳定的图像缩放。当plone.app.imaging可用时,这已经完成。否则,我们应该自己这样做。修复问题100。[maurits] (#100)

5.5.0 (2021-06-30)

新功能

  • 防止存储的XSS攻击(svg、html)。通过实现可信mimetypes的允许列表来完成此操作。您可以通过仅使用svg、html和javascript的拒绝列表来反转此操作。通过设置OS环境变量NAMEDFILE_USE_DENYLIST=1来完成此操作。来自Products.PloneHotfix20210518。[maurits] (#3274)

5.4.0 (2020-06-23)

新功能

5.3.1 (2020-04-30)

错误修复

  • 修复图像缩放,以便在不需要缩放时重用原始图像,允许Plone REST API在无需性能损失的情况下使用缓存的可缩放URL。[datakurre] (#92)

5.3.0 (2020-04-21)

新功能

  • 将使用字段值_p_mtime而不是上下文对象_p_mtime作为图像缩放无效化时间戳,以修复上下文对象(例如,具有主图像的文档)修改会使其所有图像字段缩放无效,即使图像本身未修改的问题。[datakurre] (#91)

5.2.2 (2020-04-14)

错误修复

  • 在DefaultImageScalingFactory中关闭BlobFile。[timo] (#89)

  • 在将文件传递给Pillow之前处理SVG文件,修复#3063 [sneridagh] (#3063)

5.2.1 (2019-12-11)

错误修复

  • 修复tiff支持。删除process_tiff并让PIL完成工作。[mamico] (#85)

  • 当使用PIL时修复getImageInfo中的content_type。[mamicp] (#85)

5.2.0 (2019-11-25)

新功能

  • 加载SVG文件。[balavec] (#63)

5.1.0 (2019-10-21)

新功能

  • 添加新的接口plone.namedfile.interfaces.IPluggableFileFieldValidationplone.namedfile.interfaces.IPluggableImageFieldValidation。重构:现在字段验证现在寻找具有此接口的适配器,该接口适配字段和值。所有找到的适配器都被调用。图像内容类型检查器(之前存在)现在是迄今为止唯一实现和注册的适配器。其他适配器可以在相关或自定义代码中注册。[jensens] (#81)

5.0.5 (2019-10-12)

错误修复

  • 修复未关闭文件的ResourceWarnings [mamico] (#80)

5.0.4 (2019-06-27)

错误修复

  • 现在可以更容易地自定义@@images视图。[ale-rt] (#65)

5.0.3 (2019-04-29)

错误修复

  • 增加静态MAX_INFO_BYTES以修复无法正确从具有大量元数据的图像中提取文件大小的问题。[elioschmutz] (#74)

5.0.2 (2018-11-13)

错误修复

  • 当Exif数据不良时,不要使图像上传失败。[maurits] (#68)

5.0.1 (2018-11-08)

错误修复

  • 修复对BytesIO的一个遗忘的更改。[pbauer]

5.0 (2018-11-02)

新功能

  • 针对Zope 4(仅测试更改)。

  • Python 3兼容性 [pbauer, matthewwilkes, fgrcon, jensens]

错误修复

4.2.3 (2017-09-08)

错误修复

4.2.2 (2017-07-03)

错误修复

  • 如果由于任何原因,字段名在上下文中不可用,则不要破坏DefaultImageScalingFactory。[thet]

  • 为不同的域使用不同的缓存键。[mamico]

4.2.1 (2017-05-30)

错误修复

  • 修复#46号错误,当process_png、process_jpeg和process_tiff失败时,会出现“在赋值之前引用宽度”错误。[thet]

  • 修复contentType属性应为str类型的问题,导致验证错误(修复了#38)。[rodfersou]

  • 修复了在ImageIFD.XResolution或ImageIFD.YResolution未设置时图像旋转的bug。[loechel]

  • 修复:不要将失败的PIL图像识别记录为错误,而是记录为警告。[jensens]

  • 修复:重新添加了与Plone 4的兼容性。[loechel]

4.2.0 (2017-03-26)

新功能

  • 使用srcset属性添加视网膜图像缩放。[didrix]

4.1.2 (2017-02-12)

错误修复

  • BrowserViews没有Acquisition。[pbauer]

4.1.1 (2017-01-20)

新功能

错误修复

  • 在getImageInfo中添加了对Tiff图像的处理。[loechel]

  • 重构包。将图像元数据检测移至自己的子文件夹中 [loechel]

4.1 (2016-09-14)

新功能

  • 添加Pdata存储 [vangheem]

4.0 (2016-08-12)

不兼容性

  • 仅针对Plone 5.1,coredev 5.0和4.3位于3.0.x分支 [jensens]

    • plone.supermodelplone.scaleplone.schemaeditor现在是硬依赖。由于bbb原因,setup.py中的额外部分被保留,但为空。条件代码现在不再条件化。这大大简化了代码。

    • zope.app.file不再是硬依赖。如果存在,则仍会检查其FileChunk实现,否则不会。

新功能

  • 使用适配器作为缩放工厂,类似于plone.scale>=1.5中的适配器 [jensens]

修复

  • 由于二进制文件以文本模式打开而导致Windows 10上的几个测试失败。已修复。[smcmahon]

  • 防止从与未提交的blob关联的临时文件创建文件流迭代器。通过尝试删除或访问另一个进程正在使用的文件来修复Windows 10上的“WindowsError 32”错误。[smcmahon]

  • 修复测试以与最新的plone.scale更改兼容,其中gif图像不再转换为jpeg。[thet]

  • 修复了测试设置以正确使用层。[jensens]

  • 修复了test_blobfile.py中的测试隔离问题。[jensens]

  • 修复了测试.zcml中缺少i18n:domain的警告。[gforcada]

  • 修复了一些代码分析警告。[gforcada]

3.0.8 (2016-02-26)

修复

  • 遵循PEP 8、UTF-8标题、实现/适配装饰器、doctest格式。[thet, jensens]

  • 对getImageSize方法进行工作区处理。防止返回(-1, -1)作为图像的大小。[andreesg]

3.0.7 (2016-02-12)

修复

  • 将plone.protect作为软依赖。这允许在不使用Plone堆栈的设置中使用此包。修复了plone/Products.CMFPlone#1311 [thet]

3.0.6 (2016-01-08)

修复

  • 稳定测试。[gotcha]

3.0.5 (2015-11-26)

新功能

3.0.4 (2015-10-28)

修复

  • 不再依赖于已弃用的bobobase_modification_time from Persistence.Persistent。[thet]

3.0.3 (2015-08-14)

  • scale返回None时,访问@@images视图中的tag方法不会失败。[thet]

3.0.2 (2015-03-13)

  • 当通过基于UID的URL访问图像缩放时,使用plone.stableResource规则集缓存图像缩放。(需要plone.app.imaging >= 1.1.0)[davisagli]

3.0.1 (2014-10-23)

  • 修复了在Content-Disposition标题中插入文件名的问题。[kroman0]

  • 在下载视图中也要尊重字段级别的安全性,包括主字段。[jensens]

  • 国际化字段工厂标签。[thomasdesvenain]

3.0.0 (2014-04-13)

  • 创建比例时禁用CSRF保护,这样我们就可以写入数据库。[vangheem]

2.0.5 (2014-02-19)

  • 确保在文件包中使用之前创建zope.app.file.file模块别名。[thomasdesvenain]

2.0.4 (2014-01-27)

  • 创建比例时禁用CSRF保护,这样我们就可以写入数据库。[vangheem]

  • 验证图像字段:使用MIME类型检查内容是否实际上是图像。[thomasdesvenain]

  • 修复:当contentType为空字符串时,get_contenttype仍然可以工作。

  • NamedFile与zope.app.file FileChunk的向后兼容性。避免NamedFile验证意外失败。[thomasdesvenain]

2.0.5 (2014-02-19)

  • 确保在文件包中使用之前创建zope.app.file.file模块别名。[thomasdesvenain]

2.0.4 (2014-01-27)

  • NamedFile与zope.app.file FileChunk的向后兼容性。避免NamedFile验证意外失败。[thomasdesvenain]

  • 验证图像字段:使用MIME类型检查内容是否实际上是图像。[thomasdesvenain]

  • 修复:当contentType为空字符串时,get_contenttype仍然可以工作。[thomasdesvenain]

2.0.3 (2013-12-07)

  • 缩放遍历器现在不再尝试在一次遍历中走两步。这在chameleon中是不可能的。[do3cc]

2.0.2 (2013-05-23)

  • 如果存在,则使用plone.app.imaging的(>=1.0.8)质量设置。https://dev.plone.org/ticket/13337 [khink]

  • 修复在未实现Dublin Core的上下文中无效化的错误;特别是portlet分配。回退为bobo_modification_time。也许portlet分配应该实现modified()?[tmog]

  • 修复了在Plone 4.3迁移后出现的问题,即处理TTW Dexterity内容类型图像字段数据时,如果图像数据很大并以zope.app.file.file.FileChunk的形式存储在ZODB中而不是原始字符串数据。[miohtama]

2.0.1 (2013-01-17)

  • 在缩放中添加方向参数支持(在标签和缩放函数中曾忽略)。现在,使用参数direction=’down’调用标签函数裁剪图像。默认方向为’tumbnail’,因此默认行为保持不变。[jriboux]

2.0 (2012-08-29)

  • 将文件和图像值实现移到这里,而不是扩展来自zope.app.file和z3c.blobfile的实现。这有助于解决依赖关系混乱的问题。[davisagli]

  • 基于blob的文件和图像实现现在总是可用。(但只有在Zope使用支持blob的存储时它们才会工作。)[davisagli]

  • 为@@images视图添加对HEAD请求的支持。[anthonygerrard]

  • 为文件下载视图的子类添加覆盖头部信息的钩子。[anthonygerrard]

  • 如果文件名包含非ASCII字符,则不要在头部设置文件名。[do3cc]

  • 如果jpeg文件包含损坏的元数据,则添加Dexterity Image会导致TypeError。关闭http://dev.plone.org/ticket/12753。[由joka补丁,kleist应用]

1.0.6 - 2011-10-18

  • 修复测试失败。[davisagli]

  • 修复在具有Unicode标题的项目上生成缩放标签时的错误。[tomster]

1.0.5 - 2011-09-24

  • 使下载视图尊重要下载的字段的自定义读取权限,而不仅仅是检查对象的整体视图权限。[davisagli]

1.0.4 - 2011-08-21

  • 修复在具有非ASCII字符标题的项目上生成缩放标签时的错误。[davisagli]

  • 确保在不允许的容器上可以访问允许的属性上的图像缩放。[davisagli]

  • 为safe_filename添加单元测试,因为在这个模块中没有进行练习。(应该移动到plone.formwidget.namedfile?)[lentinj]

1.0.3 - 2011-05-20

1.0.2 - 2011-05-19

  • 不要从ImageScale标签中省略空字符串属性。[elro]

1.0.1 - 2011-05-19

  • 在ImageScale的tag方法中允许省略height/width/alt/title,当它们作为None参数提供时。[elro]

  • 在打包的文件字段中,根据RFC 2231对Content-Disposition头中的filename参数进行编码。这确保了具有非ASCII字符的文件名可以成功解包。[davisagli]

  • 使各种文件类仅接受Unicode文件名。[davisagli]

1.0 - 2011-04-30

  • 使用唯一的URL访问原始缩放。[elro]

  • 避免对图像缩放使用Content-Disposition。[elro]

1.0b8 - 2011-04-12

  • 声明对plone.rfc822 >= 1.0b2的依赖(用于IPrimaryField)。[davisagli]

  • 添加一个不设置Content-Disposition的@@display-file视图,例如,这样我们就不强制下载图片。[lentinj]

1.0b7 - 2011-03-22

  • 支持以缩放比例获取原始大小。[elro]

  • 将tag()方法添加到缩放视图中。[elro]

  • 缩放:引用额外标签属性的值。[elro]

1.0b6 - 2011-02-11

  • 将主字段支持添加到@@download和@@images视图中。[elro]

  • 将getAvailableSizes和getImageSize添加到@@images视图中。[elro]

1.0b5 - 2010-04-19

  • 添加对缩放图像的支持。有关详细信息,请参阅usage.txt。[davisagli]

  • 修复字段架构,以便可以使用plone.schemaeditor添加字段。[rossp]

1.0b4 - 2009-11-17

  • 避免使用内部_current_filename()辅助函数,该函数在ZODB 3.9中已消失。[optilude]

  • 为plone.schemaeditor添加字段工厂(只有当plone.schemaeditor可用时安装)[davisagli]

1.0b3 - 2009-10-08

  • 添加plone.rfc822字段编解码器(只有当plone.rfc822可用时安装)[optilude]

1.0b2 - 2009-09-17

  • 添加plone.supermodel导入/导出处理器(只有当plone.supermodel可用时安装)。[optilude]

1.0b1 - 2009-05-30

  • 将z3c.blobfile(以及通用blob)作为软依赖。您需要单独依赖z3c.blobfile(并且可能将其锁定到版本0.1.2),以获取NamedBlobFile和NamedBlobImage字段。这意味着plone.namedfile可以与不支持BLOB的ZODB版本一起使用。此策略可能会在2.0版本中重新审视。[optilude]

1.0a1 - 2009-04-17

  • 初始发布

用法

此示例演示了如何使用该软件包。

架构字段

以下架构字段可以用来描述文件数据。如果安装了z3c.blobfile,我们只会测试字段的BLOB版本

>>> from zope.interface import Interface
>>> from plone.namedfile import field

>>> class IFileContainer(Interface):
...     simple = field.NamedFile(title=u"Named file")
...     image = field.NamedImage(title=u"Named image file")
...     blob = field.NamedBlobFile(title=u"Named blob file")
...     blobimage = field.NamedBlobImage(title=u"Named blob image file")

以下存储数据,类型如下

>>> from zope.interface import implementer
>>> from plone import namedfile


>>> @implementer(IFileContainer)
... class FileContainer(object):
...     __allow_access_to_unprotected_subobjects__ = 1
...     def __init__(self):
...         self.simple = namedfile.NamedFile()
...         self.image = namedfile.NamedImage()
...         self.blob = namedfile.NamedBlobFile()
...         self.blobimage = namedfile.NamedBlobImage()

文件数据和内容类型

现在让我们展示如何获取和设置文件数据。

FileContainer类最初创建空对象

>>> container = FileContainer()

>>> bytearray(container.simple.data)
bytearray(b'')
>>> container.simple.contentType
''
>>> container.simple.filename is None
True

>>> len(container.image.data)
0
>>> container.image.contentType
''
>>> container.image.filename is None
True

>>> len(container.blob.data)
0
>>> container.blob.contentType
''
>>> container.blob.filename is None
True
>>> len(container.blobimage.data)
0
>>> container.blobimage.contentType
''
>>> container.blobimage.filename is None
True

现在让我们在这些文件中设置一些实际数据。注意,构造函数将尝试根据文件扩展名猜测文件名

>>> container.simple = namedfile.NamedFile('dummy test data', filename=u"test.txt")
>>> bytearray(container.simple.data)
bytearray(b'dummy test data')
>>> container.simple.contentType
'text/plain'
>>> print(container.simple.filename)
test.txt

>>> container.blob = namedfile.NamedBlobFile('dummy test data', filename=u"test.txt")
>>> bytearray(container.blob.data)
bytearray(b'dummy test data')
>>> container.blob.contentType
'text/plain'
>>> print(container.blob.filename)
test.txt

让我们也尝试读取一个GIF,这是由zope.app.file测试提供的

>>> zptlogo = (
...     b'GIF89a\x10\x00\x10\x00\xd5\x00\x00\xff\xff\xff\xff\xff\xfe\xfc\xfd\xfd'
...     b'\xfa\xfb\xfc\xf7\xf9\xfa\xf5\xf8\xf9\xf3\xf6\xf8\xf2\xf5\xf7\xf0\xf4\xf6'
...     b'\xeb\xf1\xf3\xe5\xed\xef\xde\xe8\xeb\xdc\xe6\xea\xd9\xe4\xe8\xd7\xe2\xe6'
...     b'\xd2\xdf\xe3\xd0\xdd\xe3\xcd\xdc\xe1\xcb\xda\xdf\xc9\xd9\xdf\xc8\xd8\xdd'
...     b'\xc6\xd7\xdc\xc4\xd6\xdc\xc3\xd4\xda\xc2\xd3\xd9\xc1\xd3\xd9\xc0\xd2\xd9'
...     b'\xbd\xd1\xd8\xbd\xd0\xd7\xbc\xcf\xd7\xbb\xcf\xd6\xbb\xce\xd5\xb9\xcd\xd4'
...     b'\xb6\xcc\xd4\xb6\xcb\xd3\xb5\xcb\xd2\xb4\xca\xd1\xb2\xc8\xd0\xb1\xc7\xd0'
...     b'\xb0\xc7\xcf\xaf\xc6\xce\xae\xc4\xce\xad\xc4\xcd\xab\xc3\xcc\xa9\xc2\xcb'
...     b'\xa8\xc1\xca\xa6\xc0\xc9\xa4\xbe\xc8\xa2\xbd\xc7\xa0\xbb\xc5\x9e\xba\xc4'
...     b'\x9b\xbf\xcc\x98\xb6\xc1\x8d\xae\xbaFgs\x00\x00\x00\x00\x00\x00\x00\x00'
...     b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
...     b'\x00,\x00\x00\x00\x00\x10\x00\x10\x00\x00\x06z@\x80pH,\x12k\xc8$\xd2f\x04'
...     b'\xd4\x84\x01\x01\xe1\xf0d\x16\x9f\x80A\x01\x91\xc0ZmL\xb0\xcd\x00V\xd4'
...     b'\xc4a\x87z\xed\xb0-\x1a\xb3\xb8\x95\xbdf8\x1e\x11\xca,MoC$\x15\x18{'
...     b'\x006}m\x13\x16\x1a\x1f\x83\x85}6\x17\x1b $\x83\x00\x86\x19\x1d!%)\x8c'
...     b'\x866#\'+.\x8ca`\x1c`(,/1\x94B5\x19\x1e"&*-024\xacNq\xba\xbb\xb8h\xbeb'
...     b'\x00A\x00;'
...     )

>>> container.image = namedfile.NamedImage(zptlogo, filename=u"zpt.gif")
>>> container.image.data == zptlogo
True
>>> container.image.contentType
'image/gif'
>>> print(container.image.filename)
zpt.gif

>>> container.blobimage = namedfile.NamedBlobImage(zptlogo, filename=u"zpt.gif")
>>> container.blobimage.data == zptlogo
True
>>> container.blobimage.contentType
'image/gif'
>>> print(container.blobimage.filename)
zpt.gif

注意,可以强制设置MIME类型

>>> container.image = namedfile.NamedImage(zptlogo, contentType='image/foo', filename=u"zpt.gif")
>>> container.image.data == zptlogo
True
>>> container.image.contentType
'image/foo'
>>> print(container.image.filename)
zpt.gif

>>> container.blobimage = namedfile.NamedBlobImage(zptlogo, contentType='image/foo', filename=u"zpt.gif")
>>> container.blobimage.data == zptlogo
True
>>> container.blobimage.contentType
'image/foo'
>>> print(container.blobimage.filename)
zpt.gif

文件名必须设置为Unicode字符串,而不是字节字符串

>>> container.image.filename = b'foo'
Traceback (most recent call last):
...
zope.schema._bootstrapinterfaces.WrongType: ...

限制媒体类型

可以定义接受的媒体类型,就像HTML文件输入的“accept”属性一样。您可以传递文件扩展名或媒体类型值的元组

>>> class IFileContainerConstrained(Interface):
...     file = field.NamedFile(title=u"File", accept=("text/plain", ".pdf"))

>>> @implementer(IFileContainerConstrained)
... class FileContainerConstrained:
...     __allow_access_to_unprotected_subobjects__ = 1
...     def __init__(self):
...         self.file = namedfile.NamedFile()

>>> container_constrained = FileContainerConstrained()

添加有效的文件类型并检查通过。注意,验证逻辑是由框架调用的,不需要像在这个测试中那样手动调用。

>>> container_constrained.file = namedfile.NamedFile(
...     'dummy test data',
...     filename=u"test.txt"
... )
>>> IFileContainerConstrained["file"].validate(container_constrained.file)

>>> container_constrained.file = namedfile.NamedFile(
...     'dummy test data',
...     filename=u"test.pdf"
... )
>>> IFileContainerConstrained["file"].validate(container_constrained.file)

添加无效的文件类型并检查失败,返回ValidationError

>>> container_constrained.file = namedfile.NamedFile(
...     'dummy test data',
...     filename=u"test.wav"
... )
>>> IFileContainerConstrained["file"].validate(container_constrained.file)
Traceback (most recent call last):
...
plone.namedfile.field.InvalidFile: ('audio/x-wav', 'file')

下载视图

此软件包还包括一个视图,可用于下载文件。这将设置Content-Disposition,以确保浏览器下载文件而不是显示它。要使用它,链接到../context-object/@@download/fieldname,其中fieldname是在上下文对象中存储命名文件的属性名称。

我们将使用模拟请求进行测试,模拟遍历

>>> from plone.namedfile.browser import Download
>>> from zope.publisher.browser import TestRequest

>>> request = TestRequest()
>>> download = Download(container, request).publishTraverse(request, 'simple')
>>> bytearray(download())
bytearray(b'dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
'text/plain'
>>> request.response.getHeader('Content-Disposition')
"attachment; filename*=UTF-8''test.txt"

>>> request = TestRequest()
>>> download = Download(container, request).publishTraverse(request, 'blob')
>>> data = download()
>>> bytearray(hasattr(data, 'read') and data.read() or data)
bytearray(b'dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
'text/plain'
>>> request.response.getHeader('Content-Disposition')
"attachment; filename*=UTF-8''test.txt"

>>> request = TestRequest()
>>> download = Download(container, request).publishTraverse(request, 'image')
>>> download() == zptlogo
True

>>> request.response.getHeader('Content-Length')
'341'
>>> request.response.getHeader('Content-Type')
'image/foo'
>>> request.response.getHeader('Content-Disposition')
"attachment; filename*=UTF-8''zpt.gif"

>>> request = TestRequest()
>>> download = Download(container, request).publishTraverse(request, 'blobimage')
>>> data = download()
>>> (hasattr(data, 'read') and data.read() or data) == zptlogo
True
>>> request.response.getHeader('Content-Length')
'341'
>>> request.response.getHeader('Content-Type')
'image/foo'
>>> request.response.getHeader('Content-Disposition')
"attachment; filename*=UTF-8''zpt.gif"

范围支持

检查部分请求支持

>>> request = TestRequest()
>>> download = Download(container, request).publishTraverse(request, 'blobimage')
>>> data = download()
>>> request.response.getHeader('Content-Length')
'341'
>>> request.response.getHeader('Accept-Ranges')
'bytes'

请求特定范围

>>> request = TestRequest(environ={'HTTP_RANGE': 'bytes=0-99'})
>>> download = Download(container, request).publishTraverse(request, 'blobimage')
>>> data = download()
>>> request.response.getStatus()
206
>>> len(hasattr(data, 'read') and data.read() or data)
100

Content-Length标头现在指示请求范围的大小(而不是整个图像的大小)。Content-Range响应标头指示该部分消息在完整资源中的位置。

>>> request.response.getHeader('Content-Length')
'100'
>>> request.response.getHeader('Content-Range')
'bytes 0-99/341'

显示文件视图

此软件包还包括一个视图,可用于在浏览器中显示文件。要使用它,链接到../context-object/@@display-file/fieldname,其中fieldname是在上下文对象中存储命名文件的属性名称。

我们将使用模拟请求进行测试,模拟遍历

>>> from plone.namedfile.browser import DisplayFile
>>> from zope.publisher.browser import TestRequest

>>> request = TestRequest()
>>> display_file = DisplayFile(container, request).publishTraverse(request, 'simple')
>>> bytearray(display_file())
bytearray(b'dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
'text/plain'
>>> request.response.getHeader('Content-Disposition')

>>> request = TestRequest()
>>> display_file = DisplayFile(container, request).publishTraverse(request, 'blob')
>>> data = display_file()
>>> bytearray(hasattr(data, 'read') and data.read() or data)
bytearray(b'dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
'text/plain'
>>> request.response.getHeader('Content-Disposition')

>>> request = TestRequest()
>>> display_file = DisplayFile(container, request).publishTraverse(request, 'image')
>>> display_file() == zptlogo
True

>>> request.response.getHeader('Content-Length')
'341'
>>> request.response.getHeader('Content-Type')
'image/foo'

由于Content-Type未知,我们不相信它,并拒绝内联显示。我们选择下载。

>>> request.response.getHeader('Content-Disposition')
"attachment; filename*=UTF-8''zpt.gif"
>>> request = TestRequest()
>>> display_file = DisplayFile(container, request).publishTraverse(request, 'blobimage')
>>> data = display_file()
>>> (hasattr(data, 'read') and data.read() or data) == zptlogo
True
>>> request.response.getHeader('Content-Length')
'341'
>>> request.response.getHeader('Content-Type')
'image/foo'
>>> request.response.getHeader('Content-Disposition')
"attachment; filename*=UTF-8''zpt.gif"

指定主字段

要在URL中不指定字段的情况下使用@@download视图,必须使用适配器注册主字段信息。(例如,plone.dexterity框架可能已经为您完成了这项工作。)

>>> from plone.rfc822.interfaces import IPrimaryFieldInfo
>>> from zope.component import adapter

>>> @implementer(IPrimaryFieldInfo)
... @adapter(IFileContainer)
... class FieldContainerPrimaryFieldInfo(object):
...     fieldname = 'simple'
...     field = IFileContainer['simple']
...     def __init__(self, context):
...         self.value = context.simple

>>> from zope.component import getSiteManager
>>> components = getSiteManager()
>>> components.registerAdapter(FieldContainerPrimaryFieldInfo)

我们将使用模拟请求进行测试,模拟遍历

>>> request = TestRequest()
>>> download = Download(container, request)
>>> bytearray(download())
bytearray(b'dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
'text/plain'
>>> request.response.getHeader('Content-Disposition')
"attachment; filename*=UTF-8''test.txt"

图像缩放

此软件包可以处理在NamedImage或NamedBlobImage字段中存储的任意尺寸图像缩放版本的创作、存储和检索。

图像缩放通过提供plone.namedfile.interfaces.IImageScaleTraversable的任何项可用的@@images视图进行访问。您可以通过几种方式从页面模板中引用缩放。

  1. 为了完全控制,您可以显式生成标签

    <img tal:define="images context/@@images;
                     thumbnail python: images.scale('image', width=64, height=64);"
         tal:condition="thumbnail"
         tal:attributes="src thumbnail/url;
                         width thumbnail/width;
                         height thumbnail/height" />

    这将创建一个最多64 x 64像素的图像缩小版本,存储在“图像”字段中。它还允许传递plone.scale中支持的scaleImage函数的额外参数,例如modequality

  2. 为了使用额外参数自动生成标签,您将使用

    <img tal:define="images context/@@images"
         tal:replace="structure python: images.tag('image',
                      width=1200, height=800, mode='contain')" />
  3. 您可以通过调用提供plone.namedfile.interfaces.IAvailableSizes的实用程序来访问预定义的命名缩放大小,而不是每次访问缩放时都硬编码维度。缩放大小可以通过调用返回缩放名称 => (宽度,高度)字典的实用程序找到。然后可以通过以下方式访问名为“mini”的缩放

    <img tal:define="images context/@@images"
         tal:replace="structure python: images.tag('image', scale='mini')" />

    这将使用预定义的缩放大小“mini”来确定所需的图像尺寸,但仍允许传递额外参数。

  4. 可以使用方便的快捷方式来实现选项3

    <img tal:replace="structure context/@@images/image/mini" />
  5. 最后,此快捷方式也可以用于渲染未缩放的图像

    <img tal:replace="structure context/@@images/image" />

项目详情


发布历史 发布通知 | RSS源

下载文件

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

源代码分发

plone_namedfile-6.3.1.tar.gz (329.2 kB 查看散列值)

上传时间 源代码

构建分发

plone.namedfile-6.3.1-py3-none-any.whl (325.8 kB 查看散列值)

上传时间 Python 3

由以下支持