与Django一起同步读取分块上传

3 投票
2 回答
566 浏览
提问于 2025-04-17 16:49

我有一个Django应用程序,需要能够像读取文件一样读取多部分文件上传的内容,也就是说,我需要几乎是同步地访问请求对象,并且能够将其分块解压为二进制数据。 不幸的是,Django处理上传的方式是直接将文件移到内存中或临时文件里,这对我的需求来说不太合适。

有人建议我使用gevent/greenlet来处理上传,但我不太明白这和Django的关系,以及需要怎样的设置才能让它们一起工作。此外,如果在Django之外运行某些东西,我还需要实现一个数据库连接层,以验证上传是否被允许(使用票据ID)。

那么,我该如何设置呢?Django应该在一个WSGI应用程序中运行,还有人建议我写一个第二个WSGI应用程序来捕获一个特定的URL路径用于上传。我希望尽可能多地利用Django框架,同时能够同步读取上传的内容。

(我刚刚熟悉了requests这个Python库,得说我非常喜欢它,尽管我对如何在服务器环境中使用它还一无所知。)

2 个回答

1

虽然我不能为你写出所有的代码(因为这很复杂),但我可以给你推荐一个设置方案。

  1. 使用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端口用来处理上传。

  1. 我推荐使用Tornado,因为它支持流式请求体,非常适合这种用途。这里有一个可能对你有帮助的链接

  2. 你的代理设置很重要。如果你使用的是NGINX,确保关闭proxy_buffering。

  3. 我不建议使用数据库来检查票务/上传。使用Redis或memcache可能会更快。这种缓存也非常适合在Django和Tornado之间传递上传进度,因为设置/获取新值的开销会非常小。

这是一个复杂的问题,需要认真设计才能找到优雅的解决方案,但这绝对是可行的。

5

我觉得很多建议把事情搞得太复杂了。

你想改变Django处理上传文件的方式?其实只需要修改上传处理器就可以了。

这个基础类相对简单,而且提供了很多很好的扩展点。你应该可以在这个基础上进行扩展,达到你想要的效果。

撰写回答