Files and images¶
Working with file and image fields, including BLOBs
Plone has dedicated
File
and
Image
types, and it is often preferable to use these for managing
files and images. However, it is sometimes useful to treat
fields on an object as binary data. When working with
Dexterity, you can accomplish this by using
plone.namedfile
and
plone.formwidget.namedfile.
The
plone.namedfile
package includes four field types, all found in the
plone.namedfile.field
module:
-
NamedFile
stores non-BLOB files. This is useful for small files when you don’t want to configure BLOB storage. -
NamedImage
stores non-BLOB images. -
NamedBlobFile
stores BLOB files (see note below). It is otherwise identical toNamedFile
. -
NamedBlobImage
stores BLOB images (see note below). It is otherwise identical toNamedImage
.
In use, the four field types are all pretty similar. They
actually store persistent objects of type
plone.namedfile.NamedFile
,
plone.namedfile.NamedImage
,
plone.namedfile.NamedBlobFile
and
plone.namedfile.NamedBlobImage
, respectively. Note the different module! These objects
have attributes like
data
, to access the raw binary data,
contentType
, to get a MIME type, and
filename
, to get the original filename. The image values also
support
_height
and
_width
to get image dimensions.
To use the non-BLOB image and file fields, it is sufficient
to depend on
plone.formwidget.namedfile
, since this includes
plone.namefile
as a dependency. We prefer to be explicit in
setup.py
, however, since we will actually import directly from
plone.namedfile
:
install_requires=[
...
'plone.namedfile',
'plone.formwidget.namedfile',
],
Note
Again, we do not need separate
<include
/>
lines in
configure.zcml
for these new dependencies, because we use
<includeDependencies
/>
.
For the sake of illustration, we will add an image of the
speaker to the
Presenter
type. In
presenter.py
, we add:
from plone.namedfile.field import NamedBlobImage
class IPresenter(model.Schema):
...
picture = NamedBlobImage(
title=_(u"Please upload an image"),
required=False,
)
To use this in a view, we can either use a display widget
via a
DisplayForm
, or construct a download URL manually. Since we don’t have
a
DisplayForm
for the
Presenter
type, we’ll do the latter (of course, we could easily turn
the view into a display form as well).
In
presenter_templates/view.pt
, we add this block of TAL:
<div tal:define="picture nocall:context/picture"
tal:condition="nocall:picture">
<img tal:attributes="src string:${context/absolute_url}/@@download/picture/${picture/filename};
height picture/_height | nothing;
width picture/_width | nothing;"
/>
</div>
This constructs an image URL using the
@@download
view from
plone.namedfile
. This view takes the name of the field containing the file
or image on the traversal subpath (/picture
), and optionally a filename on a further sub-path. The
filename is used mainly so that the URL ends in the correct
extension, which can help ensure web browsers display the
picture correctly. We also define the
height
and
width
of the image based on the values set on the object.
Access to image scales is similar:
<div tal:define="picture nocall:context/picture"
tal:condition="nocall:picture">
<img tal:replace="structure context/@@images/picture/scale" />
</div>
where
scales
is large, preview, mini, thumb, tile, icon, or a custom
scale. This code generates a full tag, including height and
width attributes and alt and title based on the context
title. To generate just a URL, use code like:
<img tal:attributes="src string: ${context/absolute_url}/@@images/picture/scale" />
For file fields, you can construct a download URL in a
similar way, using an
<a
/>
tag, e.g.:
<a tal:attributes="href string:${context/absolute_url}/@@download/some_field/${context/some_field/filename}" />