Fork me on GitHub

Storages

Choosing the right storage implementation

There are currently only two implementations:

We recommend you to use fs on your local development box, and switch it to s3 when you deploy it to the production system.

If you need to use another storage backend, you can implement the interface by yourself: Implementing your own storage.

Using filesystem on the local development box

The most of computers have a filesystem, so using fs storage is suitable for development. It works even if you are offline.

Actually there are two kinds of filesystem storages:

FileSystemStore

It just stores the images, and simply assumes that you have a separate web server for routing static files e.g. Lighttpd, Nginx. For example, if you have a sever configuration like this:

server {
    listen 80;
    server_name images.yourapp.com;
    root /var/local/yourapp/images;
}

FileSystemStore should be configured like this:

sqlalchemy_imageattach.stores.fs.FileSystemStore(
    path='/var/local/yourapp/images',
    base_url='http://images.yourapp.com/'
)
HttpExposedFileSystemStore

In addition to FileSystemStore‘s storing features, it does more for you: actually serving files through WSGI. It takes an optional prefix for url instead of base_url:

sqlalchemy_imageattach.stores.fs.HttpExposedFileSystemStore(
    path='/var/local/yourapp/images',
    prefix='static/images/'
)

The default prefix is simply images/.

It provides wsgi_middleware() method to inject its own server to your WSGI application. For example, if you are using Flask:

from yourapp import app
app.wsgi_app = store.wsgi_middleware(app.wsgi_app)

or if Pyramid:

app = config.make_wsgi_app()
app = store.wsgi_middleware(app)

or if Bottle:

app = bottle.app()
app = store.wsgi_middleware(app)

Note

The server provided by this isn’t production-ready quality, so do not use this for your production service. We recommend you to use FileSystemStore with a separate web server like Nginx or Lighttpd instead.

Implementing your own storage

You can implement a new storage backend if you need. Every storage has to inherit Store and implement the following four methods:

put_file()

The method puts a given image to the storage.

It takes a file that contains the image blob, four identifier values (object_type, object_id, width, height) for the image, a mimetype of the image, and a boolean value (reproducible) which determines whether it can be reproduced or not.

For example, if it’s a filesystem storage, you can make directory/file names using object_type, object_id, and size values, and suffix using mimetype. If it’s a S3 implementation, it can determine whether to use RRS (reduced redundancy storage) or standard storage using reproducible argument.

get_file()

The method finds a requested image in the storage.

It takes four identifier values (object_type, object_id, width, height) for the image, and a mimetype of the image. The return type must be file-like.

It should raise IOError or its subtype when there’s no requested image in the storage.

get_url()

The method is similar to get_file() except it returns a URL of the image instead of a file that contains the image blob.

It doesn’t have to raise errors when there’s no requested image in the storage. It’s okay even if the returned URL is a broken link. Because we assume that it’s called only when the requested image is sure to be there. It means you can quickly generate URLs by just calculation without any I/O.

Moreover, you can assume that these URLs are never cached, because SQLAlchemy-ImageAttach will automatically appends a query string that contains of its updated timestamp for you.

delete_file()

The method deletes a requested image in the storage.

It takes the same arguments to get_file() and get_url() methods.

It must doesn’t raise any exception even if there’s no requested image.

The constructor of it can be anything. It’s not part of the interface.

If you believe your storage implementation could be widely used as well as for others, please contribute your code by sending a pull request! We always welcome your contributions.