[Fixed]-Django app defaults?

5👍

I’ve just created django-app-defaults based on all of the requirements. It’s basically a generalization of the second approach highlighted in the question (class Conf(object):).

Usage:

# my_app/defaults.py

# `django.conf.settings` or any other module can be imported if needed

# required
DEFAULT_SETTINGS_MODULE = True

# define default settings below
MY_DEFAULT_SETTING = "yey"

Then anywhere within your project:

from app_defaults import settings

print(settings.MY_DEFAULT_SETTING)
# yey

# All `django.conf.settings` are also available
print(settings.DEBUG)
# True

To load default setting for a single app instead of all of the apps, just do:

# Note: when apps or modules are explicitly passed,
# the `DEFAULT_SETTINGS_MODULE` var is not required

from app_defaults import Settings

settings = Settings(apps=["my_app"])

# or

from my_app import defaults
settings = Settings(modules=[defaults])
👤nitely

4👍

I have written a django package for the management of app settings called django-pluggableappsettings.

It’s a package that allows you to define sensible defaults for your settings but also adds advanced features like type checking or callable settings. It makes use of metaclasses to allow for an easy definition of the apps settings. Of course this adds an external dependency to your project.

Edit 1:

Example usage could be as follows:

Install the package using pip:

pip install django-pluggableappsettings

Create your AppSettings class in any of your project’s files. E.g. in ‘app_settings.py’.

app_settings.py

from django_pluggableappsettings import AppSettings, Setting, IntSetting

class MyAppSettings(AppSettings):
    MY_SETTING = Setting('DEFAULT_VALUE')
    # Checks for "MY_SETTING" in django.conf.settings and 
    # returns 'DEFAULT_VALUE' if it is not present

    ANOTHER_SETTING = IntSetting(42, aliases=['OTHER_SETTING_NAME'])
    # Checks for "ANOTHER_SETTING" or "OTHER_SETTING_NAME" in
    # django.conf.settings and returns 42 if it is not present.
    # also validates that the given value is of type int

Import your MyAppSettings in any file and access its attributes

from mypackage.app_settings import MyAppSettings
MyAppSettings.MY_SETTING
MyAppSettings.ANOTHER_SETTING

Note, that the settings are only initialized on first access, so if you never access a setting, its presence in django.conf.settings is never checked.

👤Tim

2👍

Problem #1: When running unit tests for the app there is no site
however, so settings wouldn’t have any of the myapp.defaults.

This problem is solved by using the testing framework that comes with django (see the documentation) as it bootstraps the test environment correctly for you.

Keep in mind that django tests always run with DEBUG=False

Problem #2: There is also a big problem if myapp.defaults needs to use
anything from settings (e.g. settings.DEBUG), since you can’t import
settings from defaults.py (since that would be a circular import).

This is not really a problem; once you import from myapp.defaults in myapp.settings, everything in settings will be in scope. So you don’t to import DEBUG, it is already available to you as its in the global scope.

0👍

When I am structuring apps, I try to define functionality in the form of mixins. Each setting should be picked up by one functionality mixin, if possible.

So in your example from above:

from django.conf import settings


class AppHomeRootMixin:
    home_root = getattr(settings, "MYAPP_HOME_ROOT", "/default/path/here")

Usage:

class MyView(AppHomeRootMixin, TemplateView):

    def dispatch(self, *args, **kwargs):
        print(self.home_root)
        return super().dispatch(*args, **kwargs)

This is really easy for another developer to see exactly what is going on, alleviates the need for third-party or first-party "magic", and allows us to think about things in terms of functionalities, rather than in terms of individual settings.

I just think that the settings layer of Django should be kept as simple as possible, and any complexity should be the responsibility of the view layer. I have run into a lot of confusing settings configurations that were created by other developers, and those configurations consumed a lot of my time when there was nobody there to explain what was going on under the hood.

Leave a comment