与Django一起同步读取分块上传
我有一个Django应用程序,需要能够像读取文件一样读取多部分文件上传的内容,也就是说,我需要几乎是同步地访问请求对象,并且能够将其分块解压为二进制数据。 不幸的是,Django处理上传的方式是直接将文件移到内存中或临时文件里,这对我的需求来说不太合适。
有人建议我使用gevent/greenlet来处理上传,但我不太明白这和Django的关系,以及需要怎样的设置才能让它们一起工作。此外,如果在Django之外运行某些东西,我还需要实现一个数据库连接层,以验证上传是否被允许(使用票据ID)。
那么,我该如何设置呢?Django应该在一个WSGI应用程序中运行,还有人建议我写一个第二个WSGI应用程序来捕获一个特定的URL路径用于上传。我希望尽可能多地利用Django框架,同时能够同步读取上传的内容。
(我刚刚熟悉了requests
这个Python库,得说我非常喜欢它,尽管我对如何在服务器环境中使用它还一无所知。)
2 个回答
虽然我不能为你写出所有的代码(因为这很复杂),但我可以给你推荐一个设置方案。
使用Tornado和Django:Tornado可以嵌入WSGI进程,这样你就可以在一个进程中同时运行Django和一个Tornado处理程序。下面是我一个正在进行的项目中的快速示例(虽然这个例子是用Tornado作为Socket.io处理程序,但它能让你大致明白解决方案的思路):
# Socket Server db = momoko.Pool(DB_DSN, **DB_CONFIG) router = tornadio2.TornadioRouter(QueryRouter, user_settings={'db':db}) sock_app = tornado.web.Application(router.urls, flash_policy_port = FL_PORT, flash_policy_file = path.join(PROJECT_ROOT, 'assets/xml/flashpolicy.xml'), socket_io_port = WS_PORT, debug=True) # Django Server os.environ['DJANGO_SETTINGS_MODULE'] = 'sever.settings' application = django.core.handlers.wsgi.WSGIHandler() container = tornado.wsgi.WSGIContainer(application) # Start the web servers if __name__ == "__main__": try: import logging tornado.options.parse_command_line() logging.getLogger().setLevel(logging.INFO) logging.info('Server started') tornado.locale.set_default_locale('us_US') http_server = tornado.httpserver.HTTPServer(container) http_server.listen(8000) tornadio2.SocketServer(sock_app, auto_start=True) tornado.ioloop.IOLoop.instance().start() except KeyboardInterrupt: tornado.ioloop.IOLoop.instance().stop() logging.info("Stopping servers.")
这可以很容易地转换为两个服务器实例,分别在两个不同的端口上运行,其中80端口留给Django,8080端口用来处理上传。
我推荐使用Tornado,因为它支持流式请求体,非常适合这种用途。这里有一个可能对你有帮助的链接。
你的代理设置很重要。如果你使用的是NGINX,确保关闭proxy_buffering。
我不建议使用数据库来检查票务/上传。使用Redis或memcache可能会更快。这种缓存也非常适合在Django和Tornado之间传递上传进度,因为设置/获取新值的开销会非常小。
这是一个复杂的问题,需要认真设计才能找到优雅的解决方案,但这绝对是可行的。