Using ZODB Blobstorage with Pyramid (repoze.bfg)

Category: Technology, Web-Applications
Tags: ,

When writing applications using Pyramid web framework a simple option to persist data is using the ZODB. It is sort of built in and very easy to ease. Although being a very stable, reliable and fast database, ZODB does not handle binary data very well. But there is a solution for this: Storing binary data (blobs) transparently outside of the database.

ZODB in newer versions has blob support built in but you need to activate it and handle it the rigth way. Here I want to share my findings and some code to make you successfully use blobs in your Pyramid application. Some parts of the code are inspired by z3c.blobfile.

Click here to display full code example

This code enables you to save binary objects to ZODB. Upon commit the binary data is transparently saved to the file system. This is done by using code like this (assuming that the module containing the code above is called blobfile.py):

[python]
import mimetypes
from blobfile import File

# assuming that we use jQuery Uploadify
data = request.POST.get(‘Filedata’)
filename = request.POST.get(‘Filename’)

obj = app.objectByUid(’123456′)

blob = File(data=data, contentType=mimetypes.guess_type(filename)[0], filename)
setattr(obj, ‘attachment’, blob)
[/python]

The only part missing is the delivery of files upon request. First lets define a route for uploads:

[xml]
path="/attachment/:uid/:fieldname"
name="download-attachment"
view=".core.downloadAttachment"/>
[/xml]

The hard work is done in the downloadAttachment method.

[python]
def downloadAttachment(context, request):
obj = app.objectByUid(request.matchdict.get(‘uid’))
blob = getattr(obj, request.matchdict.get(‘fieldname’))

res = Response(content_type=blob.contentType,
conditional_response=True)

res.headers.add(‘Content-Disposition’, ‘attachment;filename=%s’ % blob.fileName)

res.app_iter = blob # must be blob.file.File
res.content_length = blob.size
res.last_modified = blob.modified
return res
[/python]