I have following structure of my folders in Django:
./project_root
./app
./fixtures/
./static/
./templates/
./blog/
./settings.py
./urls.py
./views.py
./manage.py
./__init__.py
./plugin
./code_editor
./static
./templates
./urls.py
./views.py
./__init__.py
./code_viewer
./static
./templates
./urls.py
./views.py
./__init__.py
So, how can I make root urls.py automatically build up the list of urls by looking for other urls.py based on the INSTALLED_APPS? I change settings.py in order to build INSTALLED_APPS, TEMPLATES_DIR, STATICFILES_DIRS dynamically. (It means i do not know how many plugins will be installed in different servers. It should dynamically check it on run time and add it.)on:
python manage.py runserver
Here is code for adding INSTALLED_APPS, TEMPATES_DIR, STATICFILES_DIR.
PLUGINS_DIR = '/path_to/plugins/'
for item in os.listdir(PLUGINS_DIR):
if os.path.isdir(os.path.join(PLUGINS_DIR, item)):
plugin_name = 'app.plugins.%s' % item
if plugin_name not in INSTALLED_APPS:
INSTALLED_APPS = INSTALLED_APPS+(plugin_name,)
template_dir = os.path.join(PLUGINS_DIR, '%s/templates/' % item)
if os.path.isdir(template_dir):
if template_dir not in TEMPLATE_DIRS:
TEMPLATE_DIRS = TEMPLATE_DIRS+(template_dir,)
static_files_dir = os.path.join(PLUGINS_DIR, '%s/static/' % item)
if os.path.isdir(static_files_dir):
if static_files_dir not in STATICFILES_DIRS:
STATICFILES_DIRS = STATICFILES_DIRS + (static_files_dir,)
Any help will be appreciated. Thank you in advance.
SOLUTION:
EDIT: So what i did are as following:
I include two modules like this:
from django.conf import settings
from django.utils.importlib import import_module
And then in root urls.py I add following code:
def prettify(app):
return app.rsplit('.', 1)[1]
for app in INSTALLED_APPS:
try:
_module = import_module('%s.urls' % app)
except:
pass
else:
if 'eats.plugins' in app:
urlpatterns += patterns('',
url(r'^plugins/%s/' % prettify(app), include('%s.urls' % app))
)
Thank you a lot @Yuka. Thank you. Thank you. Thank you. Thank you.... You make my day.
What you'll want is something like this:
from django.utils.importlib import import_module
for app in settings.INSTALLED_APPS:
try:
mod = import_module('%s.urls' % app)
# possibly cleanup the after the imported module?
# might fuss up the `include(...)` or leave a polluted namespace
except:
# cleanup after module import if fails,
# maybe you can let the `include(...)` report failures
pass
else:
urlpatterns += patterns('',
url(r'^%s/' % slugify(app), include('%s.urls' % app)
)
You'll also want to steal and implement your own slugify
from django template or utils (I'm not exactly sure where it lives these days?) and slightly modify it to strip out any 'dots' and other useless namespacing you don't want in your 'url' e.g. you might not want your urls looking like so: 'example.com/plugin.some_plugin_appname/' but like example.com/nice_looking_appname/
You might even not want it automagicly named after all, and instead made a configurable 'setting' in your plugins own 'settings' module or something like so:
# plugin settings conf
url_namespace = 'my_nice_plugin_url/'
# root urls.py:
url(r'^%s/' % mod.url_namespace, include(...))
# or:
url(r'^%s/' % app.settings.url_namespace, inc..
You probably get the gist of it.
Kind regards,
I have modified the logic of @wdh and I have tested with Django 2.2.9 (latest stable in Jan 2020) and python 3.8
urls.py
from django.apps import apps
from django.conf import settings
for app in settings.INSTALLED_APPS:
if app.startswith('myappsprefix_'):
app_config = apps.get_app_config(app.rsplit('.')[0])
urlpatterns += i18n_patterns(
path(f'{app_config.urls}/', include(f'{app_config.name}.urls')),
)
i18n_patterns
is for internationalization.
apps.py of every app
class MyCustomAppsConfig(AppConfig):
name = 'myappsprefix_mycustomapp'
urls = 'mybaseurlforapp' # required!
in my settings.py
INSTALLED_APPS = [
...
'myappsprefix_mycustomapp.apps.MyCustomAppsConfig',
...
]
It is best practice not to access INSTALLED_APPS
directly as stated in django docs but to use the registry instead:
from django.apps import apps
for app in apps.get_app_configs():
app_name = app.name
try:
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With