Как загрузить файл изображения в MongoDB с помощью фреймворка Bottle и Mongoengine?

Мне нужно загрузить файл изображения в MongoDB, используя структуру mongoengine и Bottle. Вот мой код на питоне:

from bottle import Bottle, run, route, post, debug, request, template, response
from mongoengine import *


connect('imgtestdb')


app = Bottle()


class Image(Document):
    img_id = IntField()
    img_src = ImageField()


@app.route('/img/<image>')
def get_img(image):
    img = Image.objects(img_id=image)[0].img_src
    response.content_type = 'image/jpeg'

    return img


@app.route('/new')
def new_img_form():
    return template('new.tpl')


@app.post('/new')
def new_img():
    img_id = request.forms.get('id')
    img_src = request.files.get('upload')

    img = Image()
    img.img_id = img_id
    img.img_src.put(img_src, content_type = 'image/jpeg')
    img.save()



app.run(host='localhost', port=8080, debug=True, reloader=True)

И шаблон:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<form action="/new" method="post" enctype="multipart/form-data">
  Image ID: <input type="text" name="id" />
  Select a file: <input type="file" name="upload" />
  <input type="submit" value="Start upload" />
</form>
</body>
</html>

При попытке загрузить изображение выдает ошибку:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/mongoengine/fields.py", line 1311, in put
    img = Image.open(file_obj)
  File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2000, in open
    prefix = fp.read(16)
AttributeError: 'FileUpload' object has no attribute 'read'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/bottle.py", line 862, in _handle
    return route.call(**args)
  File "/usr/local/lib/python3.4/dist-packages/bottle.py", line 1728, in wrapper
    rv = callback(*a, **ka)
  File "./imgtest.py", line 38, in new_img
    img.img_src.put(img_src, content_type = 'image/jpeg')
  File "/usr/local/lib/python3.4/dist-packages/mongoengine/fields.py", line 1314, in put
    raise ValidationError('Invalid image: %s' % e)
mongoengine.errors.ValidationError: Invalid image: 'FileUpload' object has no attribute 'read'

Можно ли загрузить файл изображения из запроса бутылки в MongoDB?

Я только что попытался сохранить файл:

@app.route('/upload', method='POST')
def do_upload():
    img_id = request.forms.get('imgid')
    upload = request.files.get('upload')

    upload.save('tmp/{0}'.format(img_id))

Он возвращает ошибку:

ValueError('I/O operation on closed file',)

Затем я попытался открыть файл перед сохранением загрузки:

@app.route('/upload', method='POST')
def do_upload():
    upload = request.files.get('upload')

    with open('tmp/1.jpg', 'w') as open_file:
        open_file.write(upload.file.read())

Ошибка:

ValueError('read of closed file',)

Что я делаю неправильно?


person A. Stringfield    schedule 12.05.2014    source источник


Ответы (2)


Во-первых, img_src является экземпляром класса Bottle.FileUpload. Он не имеет read(). В основном сохраните файл и откройте снова. Сделайте тест ниже. Удачи!

import os

from bottle import route, run, template, request
from mongoengine import Document, IntField, ImageField, connect

connect('bottle')

class Image(Document):
    img_id = IntField()
    img_src = ImageField()

@route('/home')
def home():
    return template('upload')

@route('/upload', method='POST')
def do_upload():
    img_id = request.forms.get('id')
    img_src = request.files.get('upload')
    name = img_src.filename

    # your class ...
    img = Image()
    img.img_id = img_id
    # img_src is class bottle.FileUpload it not have read()
    # you need save the file
    img_src.save('.') # http://bottlepy.org/docs/dev/_modules/bottle.html#FileUpload

    # mongoengine uses PIL to open and read the file
    # https://github.com/python-imaging/Pillow/blob/master/PIL/Image.py#L2103
    # open temp file
    f = open(img_src.filename, 'r')

    # saving in GridFS...
    img.img_src.put(f)
    img.save()

    return 'OK'

run(host='localhost', port=8080, debug=True)
person horacioibrahim    schedule 12.05.2014
comment
Вернуть ValueError('I/O operation on closed file',) - person A. Stringfield; 13.05.2014
comment
Ok! Все хорошо! :) Теперь проблема с файлом. Попробуйте: stackoverflow.com/questions/18952716/ - person horacioibrahim; 13.05.2014

верно, что если img_src является экземпляром Bottle.FileUpload, у него нет метода .read()

но тогда img_src.file является _io.BufferedRandom, поэтому он имеет метод .read().

так что вы можете сделать напрямую:

file_h = img_src.file
img = Image.open(file_h)

тем не менее, попытка открыть его с помощью Pillow 2.5 Image.open() дала мне «ValueError: чтение закрытого файла» (исключение возникло из вызова Image.open() и fp.read(16) в нем)

обновление Bottle с 0.12 до 0.12.7 помогло, и это исключение исчезло. Надеюсь, поможет.

person comte    schedule 22.08.2014