pip3 install tornado motor
import bson import motor from tornado import web, gen, ioloop
db = motor.MotorClient().habr_tornado gridfs = motor.MotorGridFS(db)
class UploadHandler(web.RequestHandler): @gen.coroutine def get(self): files = yield gridfs.find({}).sort("uploadDate", -1).to_list(20) self.render('upload.html', files=files) @gen.coroutine def post(self): file = self.request.files['file'][0] gridin = yield gridfs.new_file(content_type=file.content_type) yield gridin.write(file.body) yield gridin.close() self.redirect('')
files = yield gridfs ...
visually does not get rid of synchronous files = gridfs
. But the functional difference is huge. In the case of yield
an asynchronous request to the database will occur and waiting for its completion. That is, while the database will “think”, the site will be able to handle other requests.post
method, we get the image file sent (using the form drawn in the template). Then asynchronously open the gridfs file, save the image there and close it. After this, we redirect to the same page to display the updated list of files. class ShowImageHandler(web.RequestHandler): @gen.coroutine def get(self, img_id): try: gridout = yield gridfs.get(bson.objectid.ObjectId(img_id)) except (bson.errors.InvalidId, motor.gridfs.NoFile): raise web.HTTPError(404) self.set_header('Content-Type', gridout.content_type) self.set_header('Content-Length', gridout.length) yield gridout.stream_to_handler(self)
app = web.Application([ web.url(r'/', UploadHandler), web.url(r'/imgs/([\w\d]+)', ShowImageHandler, name='show_image'), ])
([\w\d]+)
will be passed to ShowImageHandler.get
as img_id
. And the parameter name='show_image'
we will use in the template for generating URLs. app.listen(8000) ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html> <h1>Upload an image</h1> <form action="" method="post" enctype="multipart/form-data"> <input type="file" name="file" accept="image/*" onchange="javascript:this.form.submit()"> </form> <h2>Recent uploads</h2> {% for file in files %} {% set url = reverse_url('show_image', file['_id']) %} <a href="{{ url }}"><img src="{{ url }}" style="max-width: 50px;"></a> {% end %} </html>
end
instead endfor
file = self.request.files['file'][0]
. Yes, indeed, we will load the entire image file into memory before writing it into the database. And you probably think that you can use something like NginxHttpUploadModule . However, this can now be done using tornado: tornado.web.stream_request_body . Perhaps we will do this in one of the following lessons.Source: https://habr.com/ru/post/230607/
All Articles