Django“完全加载”后如何运行任意代码

时间:2022-09-11 18:21:49

I need to perform some fairly simple tasks after my Django environment has been "fully loaded".

在我的Django环境“完全加载”之后,我需要执行一些相当简单的任务。

More specifically I need to do things like Signal.disconnect() some Django Signals that are setup by my third party library by default and connect my own Signals and I need to do some "monkey patching" to add convenience functions to some Django models from another library.

更具体地说,我需要做一些事情,比如Signal.disconnect()一些Django信号,默认情况下由我的第三方库设置并连接我自己的信号,我需要做一些“猴子修补”,以便从一些Django模型中添加便利功能。另一个图书馆

I've been doing this stuff in my Django app's __init__.py file, which seems to work fine for the monkey patching, but doesn't work for my Signal disconnecting. The problem appears to be one of timing--for whatever reason the Third Party Library always seems to call its Signal.connect() after I try to Signal.disconnect() it.

我一直在我的Django应用程序的__init__.py文件中执行此操作,这似乎适用于猴子修补,但不适用于我的信号断开连接。问题似乎是时间问题 - 无论出于什么原因,第三方库在我尝试Signal.disconnect()之后似乎总是调用它的Signal.connect()。

So two questions:

所以有两个问题:

Do I have any guarantee based on the order of my INSTALLED_APPS the order of when my app's __init__.py module is loaded?

根据我的INSTALLED_APPS的顺序,我的应用程序的__init__.py模块加载时的顺序是否有任何保证?

Is there a proper place to put logic that needs to run after Django apps have been fully loaded into memory?

在Django应用程序完全加载到内存后,是否有适当的位置来放置需要运行的逻辑?

4 个解决方案

#1


6  

In Django 1.7 Apps can implement the ready() method: https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready

在Django 1.7 Apps中可以实现ready()方法:https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready

#2


5  

My question is a more poorly phrased duplicate of this question: Where To Put Django Startup Code. The answer comes from that question:

我的问题是这个问题的措辞更加糟糕:在哪里放置Django启动代码。答案来自这个问题:

Write middleware that does this in init and afterwards raise django.core.exceptions.MiddlewareNotUsed from the init, django will remove it for all requests...

编写在init中执行此操作的中间件,然后从init中提升django.core.exceptions.MiddlewareNotUsed,django将为所有请求删除它...

See the Django documentation on writing your own middleware.

有关编写自己的中间件的信息,请参阅Django文档。

#3


4  

I had to do the following monkey patching. I use django 1.5 from github branch. I don't know if that's the proper way to do it, but it works for me.

我不得不做以下猴子补丁。我从github分支使用django 1.5。我不知道这是否是正确的方法,但它对我有用。

I couldn't use middleware, because i also wanted the manage.py scripts to be affected.

我无法使用中间件,因为我还希望manage.py脚本受到影响。

anyway, here's this rather simple patch:

无论如何,这是一个相当简单的补丁:

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

and then you could use this signal like any other:

然后你可以像其他任何一样使用这个信号:

def django_apps_loaded_receiver(sender, *args, **kwargs):
    # put your code here.
django_apps_loaded.connect(django_apps_loaded_receiver)

#4


3  

As far as I know there's no such thing as "fully loaded". Plenty of Django functions include import something right in the function. Those imports will only happen if you actually invoke that function. The only way to do what you want would be to explicitly import the things you want to patch (which you should be able to do anywhere) and then patch them. Thereafter any other imports will re-use them.

据我所知,没有“满载”这样的东西。大量的Django函数包括在函数中导入一些东西。只有在实际调用该函数时才会发生这些导入。做你想做的事情的唯一方法是明确地导入你想要修补的东西(你应该可以在任何地方做),然后修补它们。此后,任何其他进口将重新使用它们。

#1


6  

In Django 1.7 Apps can implement the ready() method: https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready

在Django 1.7 Apps中可以实现ready()方法:https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready

#2


5  

My question is a more poorly phrased duplicate of this question: Where To Put Django Startup Code. The answer comes from that question:

我的问题是这个问题的措辞更加糟糕:在哪里放置Django启动代码。答案来自这个问题:

Write middleware that does this in init and afterwards raise django.core.exceptions.MiddlewareNotUsed from the init, django will remove it for all requests...

编写在init中执行此操作的中间件,然后从init中提升django.core.exceptions.MiddlewareNotUsed,django将为所有请求删除它...

See the Django documentation on writing your own middleware.

有关编写自己的中间件的信息,请参阅Django文档。

#3


4  

I had to do the following monkey patching. I use django 1.5 from github branch. I don't know if that's the proper way to do it, but it works for me.

我不得不做以下猴子补丁。我从github分支使用django 1.5。我不知道这是否是正确的方法,但它对我有用。

I couldn't use middleware, because i also wanted the manage.py scripts to be affected.

我无法使用中间件,因为我还希望manage.py脚本受到影响。

anyway, here's this rather simple patch:

无论如何,这是一个相当简单的补丁:

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

and then you could use this signal like any other:

然后你可以像其他任何一样使用这个信号:

def django_apps_loaded_receiver(sender, *args, **kwargs):
    # put your code here.
django_apps_loaded.connect(django_apps_loaded_receiver)

#4


3  

As far as I know there's no such thing as "fully loaded". Plenty of Django functions include import something right in the function. Those imports will only happen if you actually invoke that function. The only way to do what you want would be to explicitly import the things you want to patch (which you should be able to do anywhere) and then patch them. Thereafter any other imports will re-use them.

据我所知,没有“满载”这样的东西。大量的Django函数包括在函数中导入一些东西。只有在实际调用该函数时才会发生这些导入。做你想做的事情的唯一方法是明确地导入你想要修补的东西(你应该可以在任何地方做),然后修补它们。此后,任何其他进口将重新使用它们。