Dynamically loading django applications at runtime

Is it possible to dynamically load django applications at runtime? Typically, applications are loaded during initialization using the INSTALLED_APPS tuple in settings.py. However, is it possible to download additional applications at run time? I face this problem in different situations. For example, one situation occurs during testing, when I want to dynamically load or unload applications.

To make the problem more specific, imagine that I have a directory called apps where I put my applications, and I would like to automatically install any new application that appears there, without manually editing settings.py.

It is quite simple. Following the code example in

Django: dynamically add applications as a plugin, automatically create URLs and other parameters

we placed the following code in settings.py so that we could iterate over the names of all subdirectories in the application directory and increase the INSTALLED_APPS tuple in settings.py as follows:

 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, ) 

After that, if I were in a Django shell, I could be something like

 from django.conf import settings 

and applications will be listed in settings.INSTALLED_APPS . And if I did

 from django.core import management management.call_command('syncdb', interactive=False) 

this will create the necessary database tables for the applications.

However, if I now added several applications to the apps/ directory without restarting, they would not be listed in settings.INSTALLED_APPS, and therefore a subsequent call to syncdb would have no effect.

I would like to know if there is something that I could do - without restarting - to reload the settings and download / install new applications.

I tried to import my settings.py directly, i.e. from myproject import settings

and then reload these settings using inline Python after any change to the app directory. Although settings.INSTALLED_APPS is now changing to include new applications, this ultimately does not matter. For example,

 from django.db import models models.get_apps() 

shows only original applications in apps and not recently added and similarly

 management.call_command('syncdb', interactive=False) 

will not see recently added applications.

As I said above, I reflected on this situation, especially in the context of testing, where I dynamically added or removed applications.

Ps. I work with django 1.6, but on the advice of @RickyA, I see that django has some significant changes in application processing in 1.7

https://docs.djangoproject.com/en/1.7/ref/applications/

I'm still not sure what this might mean for the problem I am facing.

+12
python django django-settings django-apps
source share
4 answers

To answer my own question ...

Although I do not have a completely general solution to this problem, I have one that is sufficient to dynamically load applications during testing.

The basic solution is simple, and I found it in a small block with bikes blogs .

Continuing my example above, if I was in a django shell and wanted to add and download some new applications that were added to my apps directory, I could do

 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, ) 

and then

 loading.cache.loaded = False management.call_command('syncdb', interactive=False) 
+3
source share

Update for Django 1.8 on how to download an application that has not yet been downloaded

 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 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) 
+11
source share

Thanks for the info. I need to make the user interface itself (browser). I need to get valur from the user and create an application based on this. Is this possible in this case?

0
source share

Yes! Everything (or almost all) in Python is possible. You must use os.walk () to get all the folders, subfolders, and files in the path of your applications in order to get all your applications, including nested ones.

 def get_installed_apps(): from os import walk, chdir, getcwd previous_path = getcwd() APPS_ROOT_PATH = '/my/project/apps/folder' chdir(APPS_ROOT_PATH) for root, directories, files in walk(top=getcwd(), topdown=False): for file in files: if 'apps.py' in file: print(f"{root.replace(BASE_DIR + '/', '').replace('/', '.')}.apps") chdir(previous_path) return 
0
source share

All Articles