是否可以在运行时动态加载Django应用?通常,应用是在初始化时使用settings.py中的INSTALLED_APPS元组加载的。但是,是否可以在运行时加载其他应用程序?我在不同情况下遇到此问题。例如,一种情况是在测试期间出现的,当时我想动态加载或卸载应用程序。
为了使问题更具体,想象一下我有一个名为apps我放置应用程序的目录,并且我想自动安装安装在其中的任何新应用程序,而无需手动编辑settings.py。
apps
这很容易。遵循示例代码
Django:动态添加应用程序作为插件,自动构建网址和其他设置
我们将以下代码放入其中,settings.py从而可以遍历app目录中所有子目录的名称,并像这样增加INSTALLED_APPS元组settings.py:
settings.py
INSTALLED_APPS
APPS_DIR = '/path_to/apps/' for item in os.listdir(APPS_DIR): if os.path.isdir(os.path.join(APPS_DIR, item)): app_name = 'apps.%s' % item if app_name not in INSTALLED_APPS: INSTALLED_APPS += (app_name, )
之后,如果我在django外壳中,我可能会喜欢
from django.conf import settings
应用将列在中settings.INSTALLED_APPS。如果我做到了
from django.core import management management.call_command('syncdb', interactive=False)
这将为应用程序创建必要的数据库表。
但是,如果现在我要在apps/目录中添加更多应用程序而无需重新启动,则这些应用程序将不会在settings.INSTALLED_APPS中列出,因此后续调用syncdb无效。
apps/
syncdb
我想知道的是,是否有我可以做的事情–无需重启-重新加载设置并加载/安装新应用。
我试图直接导入my settings.py,即从myproject导入设置导入
然后reload是settings使用任何之后的蟒蛇内置app目录更改。尽管settings.INSTALLED_APPS现在已更改为包括新添加的应用程序,但这最终没有任何区别。例如,
reload
settings
from django.db import models models.get_apps()
仅显示原始应用apps,而不显示新添加的应用,同样
management.call_command('syncdb', interactive=False)
将不会看到新添加的应用。
如前所述,我在考虑动态添加或删除应用程序的测试中会考虑这种情况。
要回答我自己的问题…
尽管我没有针对此问题的完全通用的解决方案,但我确实有一个足以在测试期间动态加载应用程序的解决方案。
继续上面的示例,如果我在django shell中,并且想要添加并加载一些添加到apps目录中的新应用程序,则可以
import os from django.conf import settings from django.db.models import loading from django.core import management APPS_DIR = '/path_to/apps/' for item in os.listdir(APPS_DIR): if os.path.isdir(os.path.join(APPS_DIR, item)): app_name = 'apps.%s' % item if app_name not in settings.INSTALLED_APPS: settings.INSTALLED_APPS += (app_name, )
接着
loading.cache.loaded = False management.call_command('syncdb', interactive=False)
Django 1.8更新有关如何加载尚未加载的应用程序
from collections import OrderedDict from django.apps import apps from django.conf import settings from django.core import management new_app_name = "my_new_app" settings.INSTALLED_APPS += (new_app_name, ) # To load the new app let's reset app_configs, the dictionary # with the configuration of loaded apps apps.app_configs = OrderedDict() # set ready to false so that populate will work apps.ready = False # re-initialize them all; is there a way to add just one without reloading them all? apps.populate(settings.INSTALLED_APPS) # now I can generate the migrations for the new app management.call_command('makemigrations', new_app_name, interactive=False) # and migrate it management.call_command('migrate', new_app_name, interactive=False)