Как запустить произвольный код после полной загрузки Django

Мне нужно выполнить несколько довольно простых задач после того, как моя среда Django будет «полностью загружена».

В частности, мне нужно сделать такие вещи, как Signal.disconnect() некоторые сигналы Django, которые по умолчанию настроены моей сторонней библиотекой и connect мои собственные сигналы, и мне нужно сделать некоторые " monkey patching ", чтобы добавить удобные функции в некоторые модели Django из другой библиотеки.

Я делал это в файле __init__.py моего приложения Django, который, кажется, отлично работает для исправления обезьяны, но не работает для отключения моего сигнала. Проблема, по-видимому, связана со сроками - по какой-то причине Сторонняя библиотека всегда вызывает свой Signal.connect() после того, как я пытаюсь Signal.disconnect().

Итак, два вопроса:

Есть ли у меня какие-либо гарантии, основанные на порядке моего INSTALLED_APPS порядка загрузки модуля __init__.py моего приложения?

Есть ли подходящее место для размещения логики, которая должна запускаться после приложений Django, полностью загруженных в память?


person Chris W.    schedule 26.03.2011    source источник
comment
возможный дубликат Где разместить код запуска Django?   -  person Ned Batchelder    schedule 26.03.2011
comment
это дубликат этого: stackoverflow.com/questions/5439769/ или наоборот.   -  person Mike Ramirez    schedule 26.03.2011


Ответы (4)


В Django 1.7 приложения могут реализовать метод ready (): https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready

person guettli    schedule 27.01.2014
comment
Это работает только тогда, когда вы можете изменить settings.INSTALLED_APPS. Многие варианты использования, которые приводят к этому вопросу, лишены такой роскоши. - person Markus Unterwaditzer; 06.09.2019

Мой вопрос - это более плохо сформулированная копия этого вопроса: Где разместить стартовый код Django . Ответ исходит из этого вопроса:

Напишите промежуточное ПО, которое делает это в init, а затем вызывает django.core.exceptions.MiddlewareNotUsed из init, django удаляет его для всех запросов ...

См. Документацию Django о написании собственного промежуточного программного обеспечения..

person Chris W.    schedule 28.03.2011
comment
Я обнаружил, что это делает все по первому запросу, что ужасно ... он должен делать это при запуске. - person Pykler; 19.04.2013
comment
Согласованный. Выполнение этого по первому запросу лишает вас цели предварительной загрузки или подготовки чего-либо. - person Tobia; 24.04.2014

Пришлось сделать следующий патч обезьяны. Я использую django 1.5 из ветки github. Не знаю, правильно ли это делать, но у меня он работает.

Я не мог использовать промежуточное ПО, потому что я также хотел, чтобы это повлияло на скрипты manage.py.

во всяком случае, вот этот довольно простой патч:

import django
from django.db.models.loading import AppCache

django_apps_loaded = django.dispatch.Signal()

def populate_with_signal(cls):
    ret = cls._populate_orig()
    if cls.app_cache_ready():
        if not hasattr(cls, '__signal_sent'):
            cls.__signal_sent = True
            django_apps_loaded.send(sender=None)
    return ret

if not hasattr(AppCache, '_populate_orig'):
    AppCache._populate_orig = AppCache._populate
    AppCache._populate = populate_with_signal

и тогда вы можете использовать этот сигнал как любой другой:

def django_apps_loaded_receiver(sender, *args, **kwargs):
    # put your code here.
django_apps_loaded.connect(django_apps_loaded_receiver)
person toudi    schedule 22.01.2013
comment
Интересный. Мне нравится, что это работает для management команд, но здесь доступно так много защищенных атрибутов, что я бы побеспокоился о том, что он не может сломаться между версиями Django. - person Chris W.; 22.01.2013
comment
Фактически, единственный защищенный атрибут, специфичный для django, - это AppCache._populate. Остальное - мое собственное изобретение;) До сих пор (django1.5) более чистого способа сделать это, похоже, не существует. и поверьте мне, я бы хотел, чтобы он был чистым. я нашел билет django: code.djangoproject.com/ticket/3591, и я также нашел этот файл на github: github.com/ptone/django/blob /app-loading/django/apps/signals.py, однако, поскольку это форк, я не рискую использовать его, если он не является официальной частью django. - person toudi; 23.01.2013
comment
Куда лучше всего бросить эту обезьяну ... urls.py - person Pykler; 19.04.2013
comment
на самом деле у меня есть отдельное приложение django, называемое сигналами, и оно последнее в списке INSTALLED_APPS. Этот патч попадает в файл signal :: models.py. Когда вы используете urls.py, скрипты manage.py не пострадают (и для меня это было нежелательным решением) - person toudi; 24.07.2013
comment
Хорошие вещи - спасибо. Я обнаружил, что cls.app_cache_ready () в populate_with_signal всегда возвращал False, поэтому сигнал никогда не отправлялся. Я попытался обойти это, удалив cls.app_cache_ready () и вызвав django.db.models.get_models (), как только я подключил свой приемник сигнала к django_apps_loaded, в надежде, что get_models заставит AppCache затем заселятся. Кажется, пока это работает (я использую django 1.5.1) - person jcdude; 29.01.2014

Насколько я знаю, нет такого понятия, как «полная загрузка». Множество функций Django включают import something прямо в функцию. Этот импорт будет происходить только в том случае, если вы действительно вызовете эту функцию. Единственный способ сделать то, что вы хотите, - это явно импортировать то, что вы хотите исправить (что вы должны иметь возможность делать где угодно), а затем исправить их. После этого любой другой импорт будет использовать их повторно.

person Ben Jackson    schedule 26.03.2011
comment
Использование этого для выполнения запросов к базе данных по существующим данным не работало с SQL при тестировании памяти :( - person leech; 08.05.2013