Синхронное чтение многокомпонентной загрузки вместе с Django

У меня есть приложение Django, которому требуется доступ к чтению многокомпонентных файловых загрузок в виде файловоподобных объектов по мере их загрузки, что означает, что мне нужен более или менее синхронный доступ к объекту запроса и способу распаковать его кусками в бинарные данные. К сожалению, Django обрабатывает загрузки, перемещая их непосредственно в память или во временные файлы, что не подходит для моего варианта использования.

Кто-то рекомендовал мне использовать gevent/greenlet для обработки загрузки, но я не уверен, как это влияет на уравнение и какая настройка требуется вместе с Django, чтобы он работал. Кроме того, запуск чего-то вне Django означал бы, что мне пришлось бы реализовать уровень подключения к базе данных, чтобы проверить, разрешена ли загрузка (используя идентификатор билета).

С учетом сказанного, как я могу это настроить? Django должен работать в приложении WSGI, и кто-то также порекомендовал написать второе приложение WSGI для захвата одного URL-пути для загрузки. Я хотел бы, по сути, максимально использовать преимущества платформы Django, имея возможность синхронно читать загрузки?

(Я только что познакомился с библиотекой requests Python и должен сказать, что являюсь ее большим поклонником, хотя я ничего не знал об ее использовании в контексте сервера.)


person Naftuli Kay    schedule 22.02.2013    source источник


Ответы (2)


Я считаю, что многие из этих предложений слишком усложняют вещи.

Вам нужно изменить способ, которым Django обрабатывает загруженные файлы? Просто измените обработчик загрузки.

базовый класс относительно прост, и дает вам много отличных крючков. Вы должны иметь возможность расширить его, чтобы делать то, что вы хотите.

person Hamms    schedule 04.03.2013
comment
У меня должен быть RTFM. Фейспалм. - person Naftuli Kay; 05.03.2013
comment
Ха-ха, это получает лучшее из нас. - person Hamms; 05.03.2013

Хотя я не могу написать весь код за вас (это сложно), вот моя рекомендуемая установка.

  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, поскольку накладные расходы на установку/получение нового значения были бы очень малы.

Это большая волосатая проблема, которая потребует серьезной инженерии, чтобы придумать что-то элегантное, но это более чем выполнимо.

person Jack Shedd    schedule 27.02.2013
comment
Включил ли Tornado патч для тела запроса потоковой передачи? Похоже, что код, упомянутый в Gist, на самом деле использует форк Tornado, который не может быть возвращен обратно в основной репозиторий. - person Naftuli Kay; 27.02.2013
comment
Не уверен на 100%. Возможно, вам придется разветвить его и применить патч к вашему форку. Не большая сделка. - person Jack Shedd; 27.02.2013
comment
Да. Как обрабатывается маршрутизация URL? IE: Могу ли я беспрепятственно направить ^upload/anon/[a-zA-Z0-9]{32}$ в Tornado, а все остальное в Django? - person Naftuli Kay; 28.02.2013
comment
Хм. Возможно, но это потребует немного больше работы. Вам нужно будет специально передавать запросы для любого URL-адреса, сервер Tornado не заботится о контейнере WGSI для Django. - person Jack Shedd; 01.03.2013