Django: Выполнить код только для `manage.py runserver`, а не для `миграции`, `справки» и т. Д

#python #django #server #neural-network

#python #django #сервер #нейронная сеть

Вопрос:

Мы используем Django в качестве серверной части для веб-сайта, который предоставляет различные функции, среди прочего, используя нейронную сеть, использующую Tensorflow для ответа на определенные запросы.

Для этого мы создали AppConfig и добавили загрузку конфигурации этого приложения INSTALLED_APPS в Django settings.py . Этот AppConfig затем загружает Нейронную сеть, как только она будет инициализирована:

settings.py:

 INSTALLED_APPS = [
...
    'bert_app.apps.BertAppConfig',
]
 

…/bert_apps/app.py:

 class BertAppConfig(AppConfig):
    name = 'bert_app'
    if 'bert_app.apps.BertAppConfig' in settings.INSTALLED_APPS:
        predictor = BertPredictor() #loads the ANN.
 

Теперь, пока это работает и делает то, что должно, ANN теперь загружается для каждого выполнения отдельной команды manage.py . Хотя мы, конечно, хотим, чтобы он выполнялся при вызове manage.py runserver , мы не хотим, чтобы он выполнялся для manage.py migrate или manage.py help и всех других команд.

Я вообще не уверен, правильно ли это загружать ANN для Django-серверной части в целом, так есть ли у кого-нибудь какие-нибудь советы, как это сделать правильно? Я могу себе представить, что загрузка модели при запуске — не совсем лучшая практика, и я очень открыт для предложений о том, как сделать это правильно.

manage.py runserver Однако, помимо фактической загрузки модели, есть и другой код, который также занимает несколько секунд и который, безусловно, должен выполняться сразу после запуска сервера (и так далее manage.py help ), но также не включен (поскольку это также занимает несколько секунд), так что есть ли какой-нибудь быстрыйисправлено, как указать Django выполнять его только для runserver , а не для других его команд?

Комментарии:

1. Ваши фрагменты кода выглядят так, как будто вы смешивали код Django и Flask.

2. «Я вообще не уверен, что это правильный способ загрузки» -> как правило, правильный способ инициализации любых дополнительных функций — из вашего AppConfig. Однако обратите внимание, что это будет сделано перед разветвлением. В зависимости от используемого вами веб-сервера у вас может быть несколько процессов, и они могут быть остановлены посередине. Таким образом, если ваша нейронная сеть должна сохранять некоторые данные в оперативной памяти во всех запросах, то вам может потребоваться совершенно другой подход.

3. @KlausD. Почему ты так думаешь? Что для вас похоже на код Flask?

4. @Art То есть вы имеете в виду, что в целом то, что мы здесь сделали, правильно до тех пор, пока мы не используем несколько процессов? Что бы вы предложили на случай, если мы это сделаем? Мое первоначальное предложение состояло в том, чтобы использовать модель в качестве микросервиса, но команда сказала мне, что это будет чрезмерно…

5. @ChrisStenkamp ну, вы также всегда можете выстрелить себе в ногу без многопроцессорной обработки 🙂 То, что вы сделали, правильно, если вам не нужно сохранять измененное состояние ANN между запросами. Во-первых, ответьте на следующий вопрос: обновляют ли запросы ваше состояние ANN в памяти таким образом, что вы хотите увидеть это обновленное состояние при выполнении следующего веб-запроса? Если нет, продолжайте то, что вы делаете. Если да, что ж, все становится сложнее: вам нужно запускать ANN отдельно (например, в отдельном manage.py команда) и использовать некоторую форму IPC / RPC для связи с ним.

Ответ №1:

У меня была похожая проблема, я решил ее проверкой argv .

 class SomeAppConfig(AppConfig):

    def ready(self, *args, **kwargs):
        is_manage_py = any(arg.casefold().endswith("manage.py") for arg in sys.argv)
        is_runserver = any(arg.casefold() == "runserver" for arg in sys.argv)

        if (is_manage_py and is_runserver) or (not is_manage_py):
            init_your_thing_here()
 

Теперь немного ближе к if not is_manage_py сути: в рабочей среде вы запускаете свой веб-сервер с помощью uwsgi/ uvicorn/ …, который по-прежнему является веб-сервером, за исключением того, что он не запускается manage.py . Скорее всего, это единственное, без чего вы когда-либо будете бегать manage.py


Используйте AppConfig.ready() — это предназначено для этого:

Подклассы могут переопределять этот метод для выполнения задач инициализации, таких как регистрация сигналов. Он вызывается, как только реестр будет полностью заполнен. — [документация django]

Чтобы получить свою AppConfig спину, используйте:

 from django.apps import apps
apps.get_app_config(app_name)
# apps.get_app_configs()  # all
 

Комментарии:

1. Спасибо, кажется, это работает! 🙂 Однако одно но: пока мы даже не создаем экземпляр AppConfig (как вы видите в вопросе, predictor это просто атрибут класса). Поэтому, когда мы используем его, мы используем from bert_app.apps import BertAppConfig BertAppConfig.predictor.do_stuff() в другом месте. В вашем ответе AppConfig, похоже, является ООП. Как мы могли бы получить доступ к экземпляру этого позже? Может быть, синглтон-паттерн? И когда ready() будет вызван Django?

2. @ChrisStenkamp django создаст для вас его экземпляр. Используйте ready() метод, он специально создан для этого. Чтобы получить объект, который вы создали внутри вашего AppConfig , просто получите ваш AppConfig , или даже сохраните его в какой-нибудь глобальной переменной для всего модуля (лучше не в apps.py , а где-нибудь еще). И, пожалуйста, пожалуйста, не внедряйте свои собственные синглтоны в Python — для этого есть модули. Я обновил ответ информацией об AppConfig этом.

Ответ №2:

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

 def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'slambook.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)
    # check if has runserver
    if `runserver` in sys.argv:
        #execute your custom function


if __name__ == '__main__':
    main()
 

вы можете проверить sys.argv , есть ли у него runserver , если да, то выполните свой скрипт или функцию

Комментарии:

1. Но, делая это таким образом, ничего не загружается в другие команды, кроме runserver, и, например help , команды просто завершаются, ничего не возвращая..