This How-to applies to:
1.0
This How-to is intended for: Developer
This How-to is intended for: Developer
If you want to handle files in zope, you can use the zope.app.file and zope.file packages.
zope.app.file
Using zope.app.file is a simple way to implement a file uploading feature. If you don't upload large file, it may be enough for you. If you use filestorage, all file data will be stored in the Data.fs. If you are uploading large files, it will consume lots of memory resources.Edit the configuration file
Add zope.app.file to setup.pyinstall_requires=['setuptools',
'grok',
'grokui.admin',
'z3c.testsetup',
'zope.app.file',
# Add extra requirements here
],
In a more formal development setting, or if you wish to ensure that you can recreate your exact development environment at a later date, you may wish to pin the zope.app.file package to the specific version you are developing against in your buildout.cfg. You can do this by adding:
[versions]
zope.app.file = 3.4.4
Implement uploading form
Make a Container object to hold uploaded file(s). filecontainer.py is very simple.import grok
class FileContainer(grok.Container):
pass
import grok
import zope.app.file
from zope.app.container.interfaces import INameChooser
class FileContainer(grok.Container):
pass
class Upload(grok.AddForm):
grok.context(FileContainer)
form_fields = grok.AutoFields(zope.app.file.interfaces.IFile).select('data')
@grok.action('Add file')
def add(self, data):
self.upload(data)
self.redirect(self.url(self.context.__parent__))
def upload(self, data):
fileupload = self.request['form.data']
if fileupload and fileupload.filename:
contenttype = fileupload.headers.get('Content-Type')
file_ = zope.app.file.file.File(data, contenttype)
# use the INameChooser registered for your file upload container
filename = INameChooser(container).chooseName(fileupload.filename)
self.context[filename] = file_
For example to provide a name chooser which converts leading + and @ characters to 'plus-' and 'at-' text only in the context of uploading files into your FileContainer:
from zope.app.container.interfaces import INameChooser
from zope.app.container.contained import NameChooser
class PrimitiveFilenameChangingNameChooser(grok.Adapter, NameChooser):
grok.implements(INameChooser)
grok.context(FileContainer)
def chooseName(self, name):
if name.startswith('+'):
name = 'plus-' + name[1:]
if name.startswith('@'):
name = 'at-' + name[1:]
You can create a working sample upload application by implementing the following code in a python file:
import grok
import zope.app.file
from zope.app.container.interfaces import INameChooser
from zope.app.container.contained import NameChooser
class FileUploadApp(grok.Application, grok.Container):
def __init__(self):
super(FileUploadApp, self).__init__()
self['files'] = FileContainer()
class FileContainer(grok.Container):
pass
class Index(grok.View):
grok.context(FileUploadApp)
def render(self):
response = "<html><head></head><body><h1>File List</h1><a href='upload'>Upload File</a><ul>"
for filename in self.context['files'].keys():
response += "<li><a href='files/" + filename + "'>" + filename + "</li>"
response += "</ul></body></html>"
return response
class Upload(grok.AddForm):
grok.context(FileUploadApp)
form_fields = grok.AutoFields(zope.app.file.interfaces.IFile).select('data')
@grok.action('Upload')
def add(self, data):
if len(data) > 0:
self.upload(data)
self.redirect(self.url(self.context))
def upload(self, data):
fileupload = self.request['form.data']
if fileupload and fileupload.filename:
contenttype = fileupload.headers.get('Content-Type')
file_ = zope.app.file.file.File(data, contenttype)
# use the INameChooser registered for your file upload container
filename = INameChooser(self.context['files']).chooseName(fileupload.filename, None)
self.context['files'][filename] = file_
class PrimitiveFilenameChangingNameChooser(grok.Adapter, NameChooser):
grok.context(FileUploadApp)
grok.implements(INameChooser)
grok.adapts(FileContainer)
def chooseName(self, name):
if name.startswith('+'):
name = 'plus-' + name[1:]
if name.startswith('@'):
name = 'at-' + name[1:]
zope.file
Next is zope.file. This is more efficient than zope.app.file, but requires blob storage.Edit the configuration file
The buildout created by Grokproject is already configured to handle Blob storage. If you want to change the location of the blob storage directory, you can edit the buildout.cfg file under the "zope_conf" section.[zope_conf]
recipe = collective.recipe.template
input = etc/zope.conf.in
output = ${buildout:parts-directory}/etc/zope.conf
filestorage = ${buildout:directory}/var/filestorage
blobstorage = ${buildout:directory}/var/blobstorage
Next, Add zope.file and zope.mimetype to setup.py.
install_requires=['setuptools',
'grok',
'grokui.admin',
'z3c.testsetup',
'zope.file',
'zope.mimetype',
# Add extra requirements here
],
Implement uploading form for FileContainer class and view form for File class
We will use the same filecontainer.py and FileContainer class, but modify them to use zope.file in a working sample application:import grok
import zope.schema
import zope.file.file
import zope.file.upload
import zope.file.download
from zope.app.container.interfaces import INameChooser
from zope.app.container.contained import NameChooser
class FileUploadApp(grok.Application, grok.Container):
def __init__(self):
super(FileUploadApp, self).__init__()
self['files'] = FileContainer()
class FileContainer(grok.Container):
pass
class Upload(grok.AddForm):
grok.context(FileUploadApp)
form_fields = grok.Fields(
zope.schema.Bytes(__name__='data',
title=u'Upload data',
description=u'Upload file',),
)
@grok.action('Upload')
def add(self, data):
if len(data) > 0:
self.upload(data)
self.redirect(self.url(self.context))
def upload(self, data):
fileupload = self.request['form.data']
if fileupload and fileupload.filename:
contenttype = fileupload.headers.get('Content-Type')
file_ = zope.file.file.File()
zope.file.upload.updateBlob(file_, fileupload)
# use the INameChooser registered for your file upload container
filename = INameChooser(self.context['files']).chooseName(fileupload.filename, None)
self.context['files'][filename] = file_
class Index(grok.View):
grok.context(FileUploadApp)
def render(self):
response = "<html><head></head><body><h1>File List</h1><a href='upload'>Upload File</a><ul>"
for filename in self.context['files'].keys():
response += "<li><a href='files/" + filename + "'>" + filename + "</li>"
response += "</ul></body></html>"
return response
class PrimitiveFilenameChangingNameChooser(grok.Adapter, NameChooser):
grok.context(FileUploadApp)
grok.implements(INameChooser)
grok.adapts(FileContainer)
def chooseName(self, name):
if name.startswith('+'):
name = 'plus-' + name[1:]
if name.startswith('@'):
name = 'at-' + name[1:]
class FileIndex(zope.file.download.Display, grok.View):
grok.name('index.html')
grok.context(zope.file.file.File)
def render(self):
return self()
No comments:
Post a Comment