如何在Django "完全加载" 后运行任意代码
我需要在我的Django环境“完全加载”后执行一些相对简单的任务。
具体来说,我需要做一些事情,比如用Signal.disconnect()
来断开一些由第三方库默认设置的Django信号,然后连接我自己的信号。此外,我还需要做一些“猴子补丁”,为另一个库中的一些Django模型添加方便的功能。
我一直在我的Django应用的__init__.py
文件中做这些事情,这样做对猴子补丁来说似乎没问题,但对断开信号就不行。问题似乎出在时机上——不知为何,第三方库总是在我尝试用Signal.disconnect()
断开信号之后才调用它的Signal.connect()
。
所以有两个问题:
根据我的INSTALLED_APPS
的顺序,我能保证我的应用的__init__.py
模块加载的顺序吗?
有没有合适的地方可以放置那些需要在Django应用完全加载到内存后执行的逻辑?
4 个回答
我需要做一些“猴子补丁”的工作。我用的是从GitHub分支上下载的django 1.5。我不知道这样做是否正确,但对我来说是有效的。
我不能使用中间件,因为我还想让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)
我的问题其实是对这个问题的一个不太清晰的重复提问:Django 启动代码应该放在哪里。这个问题的答案是:
写一个中间件,在初始化的时候执行这个操作,然后在初始化中抛出 django.core.exceptions.MiddlewareNotUsed,Django 会在所有请求中把它移除...
可以查看 Django 的关于编写自定义中间件的文档。
在Django 1.7版本中,应用程序可以实现一个叫做ready()的方法:https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready