django settings per application - best practice?

this is somewhat related to this question
Why is django's settings object a LazyObject?

In my django project i have several applications. Each application can have its own non-trivial settings file.

proj/
    proj/
         settings.py
    app/
         settings.py
         views.py

What is the general best practice here?
should app/settings.py do

from django.conf import settings
APP_SETTING= lambda: settings.getattr('APP_SETTING', 'custom_value')
PROJ_SETTING= lambda: settings.PROJ_SETTING

and then in app/views.py do

import .settings 
X = settings.APP_SETTING
Y = settings.PROJ_SETTING

or should I be modifying the django lazy settings object in app/settings.py as per the django coding style?

from django.conf import settings
# not even sure how I would check for a default value that was specified in proj/settings.py
settings.configure(APP_SETTING='custom_value')

and then each app/views.py just consumes proj/settings.py via django.conf settings?

from django.conf import settings
X = settings.APP_SETTING
Y = settings.PROJ_SETTING

There are obviously quite a few other permutations but I think my intent is clear.
Thanks in advance.


Solution 1:

The simplest solution is to use the getattr(settings, 'MY_SETTING', 'my_default') trick that you mention youself. It can become a bit tedious to have to do this in multiple places, though.

Extra recommendation: use a per-app prefix like MYAPP_MY_SETTING.

There is a django app, however, that gets rid of the getattr and that handles the prefix for you. See http://django-appconf.readthedocs.org/en/latest/

Normally you create a conf.py per app with contents like this:

from django.conf import settings
from appconf import AppConf

class MyAppConf(AppConf):
    SETTING_1 = "one"
    SETTING_2 = (
        "two",
    )

And in your code:

from myapp.conf import settings

def my_view(request):
    return settings.MYAPP_SETTINGS_1  # Note the handy prefix

Should you need to customize the setting in your site, a regular entry in your site's settings.py is all you need to do:

MYAPP_SETTINGS_1 = "four, four I say"

Solution 2:

Since Django 1.7 there is a django-based structure for app-oriented configurations! You could find descriptive solution here

In this new structure, conventionally you could have an apps.py file in your applications' folder which are embeded in project, something like this:

proj/
    proj/
         settings.py
    app1/
        apps.py
        views.py
    app2/
        apps.py
        views.py

app1/apps.py file could include something like this:

from django.apps import AppConfig


class App1Config(AppConfig):
    # typical systemic configurations
    name = 'app1'
    verbose_name = 'First App'

    # your desired configurations
    OPTION_A = 'default_value'
    APP_NAMESPACE = 'APP'
    APP_OPTION_B = 4

you could have app2/apps.py something different like this:

from django.apps import AppConfig


class App2Config(AppConfig):
    # typical systemic configurations
    name = 'app2'
    verbose_name = 'Second App'

    # your desired configurations
    OTHER_CONFIGURATION = 'default_value'
    OPTION_C = 5

and so etc for other apps.pys in you Django Application folder.

It's important that you should import applications you included apps.py in, as follows:

# proj/settings.py

INSTALLED_APPS = [
    'app1.apps.App1Config',
    'app2.apps.App2Config',
    # ...
]

‌Now, You could access desired app-based configuration someway like this:

from django.apps import apps
apps.get_app_config('app1').OPTION_A