Reputation: 10879
Desired Behaviour
Upload an image to GridFS and then show it in the browser (just to get an idea of how GridFS works).
Current Behaviour
Image is uploaded to GridFS collections (I can access it via the shell) and then a 500 error is returned.
Error
Error: 500 Internal Server Error
Sorry, the requested URL 'https:/mysite.com/form_action_path' caused an error:
Form
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="data" />
<input type="submit" value="submit">
</form>
Bottle
# relevant libraries
import gridfs
from bottle import response
@route('/upload', method='POST')
def do_upload():
data = request.files.data
name, ext = os.path.splitext(data.filename)
if ext not in ('.png','.jpg','.jpeg'):
return "File extension not allowed."
if data and data.file:
raw = data.file.read()
filename = data.filename
dbname = 'grid_files'
db = connection[dbname]
fs = gridfs.GridFS(db)
fs.put(raw,filename=filename)
# this is the part where I am trying to get the image back out
collection = db.fs.files
cursor = collection.find_one({"filename":"download (1).jpg"})
response.content_type = 'image/jpeg'
return cursor
return "You missed a field."
Edit:
This returns an image in the browser:
# .... same as above
# this is the part where I am trying to get the image back out
thing = fs.get_last_version(filename=filename)
response.content_type = 'image/jpeg'
return thing
My remaining questions would be:
chunks
in the data
field of the fs.chunks
collection documents? Upvotes: 2
Views: 3832
Reputation: 24017
The initial code doesn't work because you're returning a document, which PyMongo represents as a Python dictionary. Flask doesn't know what to do with it. (Note that find_one() returns a single document, and find() returns a Cursor.)
Your final code returns the "thing" it gets from GridFS.get_last_version(), which is a GridOut object for reading from a GridFS file.
GridOut is iterable: iterating a GridOut obtains chunks of byes. Flask does know how to turn an iterable into an HTTP response, so the second version of your code works.
The lesson is: when you want to interact with GridFS, use the GridFS class rather than find() or find_one().
Yes, the image consists of merged chunks
data from the fs.chunks
collection.
To include the image in an <img>
tag, something like this should work:
@route('/images/<filename>')
def image(filename):
fs = gridfs.GridFS(db)
gridout = fs.get_last_version(filename=filename)
response.content_type = 'image/jpeg'
return gridout
Then in your HTML, <img src="/images/filename.jpg">
.
Upvotes: 2