William Nakagawa
William Nakagawa

Reputation: 266

How to upload and save a file using bottle framework

HTML:

<form action="/upload" method="post" enctype="multipart/form-data">
  Category:      <input type="text" name="category" />
  Select a file: <input type="file" name="upload" />
  <input type="submit" value="Start upload" />
</form>

View:

@route('/upload', method='POST')
def do_login():
    category   = request.forms.get('category')
    upload     = request.files.get('upload')
    name, ext = os.path.splitext(upload.filename)
    if ext not in ('png','jpg','jpeg'):
        return 'File extension not allowed.'

    save_path = get_save_path_for_category(category)
    upload.save(save_path) # appends upload.filename automatically
    return 'OK'

I'm trying to do this code but it is not working. What I'm doing wrong?

Upvotes: 23

Views: 27150

Answers (2)

FrViPofm
FrViPofm

Reputation: 353

It is also possible to store files in databases.

Macaron is a common ORM (Object-Relational Mapper) for Bottle and SQLite but has no binary field type. We have to create it until Macaron get one (see here).

from macaron import Field

class BinaryField(Field):
    TYPE_NAMES = ("BLOB")
    SQL_TYPE = "BLOB"

    def __init__(self, max_length=None, min_length=None, length=None, **kw):
        super(BinaryField, self).__init__(**kw)
        self.max_length, self.min_length = max_length, min_length
        self.length = length
        if self.length and not self.max_length: self.max_length = self.length
        self.type = self.SQL_TYPE

We need to create a model, say Icon :

from macaron import Model, SerialKeyField, CharField, 
            
class Icon (Model):
    id           = SerialKeyField( primary_key=True )
    filename     = CharField( max_length=36 )
    category     = CharField( max_length=36 )
    mime         = CharField( max_length=36, null=True )
    data         = BinaryField(  )

And then, in the controler, to record the uploaded icon :

import os
import macaron

# [...]
# see bottle and macaron docs

mimes = {
  '.png':"image/png",
  '.jpeg':"image/jpeg",
  '.jpg':"image/jpeg",
}

@route('/upload', method='POST')
@view('icons')
def do_upload():
    upload = request.files.get('upload')
    name, ext = os.path.splitext(upload.filename)
    if upload != None & ext in  mimes.keys() :
        icon = Icon.create(
            filename = upload.filename,
            category = request.forms.get('category'),
            data = upload.file.read(),
            mime = mimes[ext])
        macaron.bake()
    return dict(
        icons = Icon.all()
    )

Send the file with :

@route('/icon/<id:int>')
def icon(id):
    icon = Icon.get(id)
    response.set_header('Content-Type', icon.mime)
    return icon.data

Upvotes: 0

Stanislav
Stanislav

Reputation: 856

Starting from bottle-0.12 the FileUpload class was implemented with its upload.save() functionality.

Here is example for the Bottle-0.12:

import os
from bottle import route, request, static_file, run

@route('/')
def root():
    return static_file('test.html', root='.')

@route('/upload', method='POST')
def do_upload():
    category = request.forms.get('category')
    upload = request.files.get('upload')
    name, ext = os.path.splitext(upload.filename)
    if ext not in ('.png', '.jpg', '.jpeg'):
        return "File extension not allowed."

    save_path = "/tmp/{category}".format(category=category)
    if not os.path.exists(save_path):
        os.makedirs(save_path)

    file_path = "{path}/{file}".format(path=save_path, file=upload.filename)
    upload.save(file_path)
    return "File successfully saved to '{0}'.".format(save_path)

if __name__ == '__main__':
    run(host='localhost', port=8080)

Note: os.path.splitext() function gives extension in ".<ext>" format, not "<ext>".

  • If you use version previous to Bottle-0.12, change:

    ...
    upload.save(file_path)
    ...
    

to:

    ...
    with open(file_path, 'wb') as open_file:
        open_file.write(upload.file.read())
    ...
  • Run server;
  • Type "localhost:8080" in your browser.

Upvotes: 40

Related Questions