File: django_dynaconf_v2.py

package info (click to toggle)
python-dynaconf 3.2.12-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,900 kB
  • sloc: python: 21,464; sh: 9; makefile: 4
file content (144 lines) | stat: -rw-r--r-- 4,699 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""Dynaconf django extension

In the `django_project/settings.py` put at the very bottom of the file:

# HERE STARTS DYNACONF EXTENSION LOAD (Keep at the very bottom of settings.py)
# Read more at https://www.dynaconf.com/django/
import dynaconf  # noqa
settings = dynaconf.DjangoDynaconf(__name__)  # noqa
# HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line)

Now in the root of your Django project
(the same folder where manage.py is located)

Put your config files `settings.{py|yaml|toml|ini|json}`
and or `.secrets.{py|yaml|toml|ini|json}`

On your projects root folder now you can start as::

    DJANGO_DEBUG='false' \
    DJANGO_ALLOWED_HOSTS='["localhost"]' \
    python manage.py runserver
"""

from __future__ import annotations

import inspect
import os
import sys

import dynaconf
from dynaconf.hooking import HookableSettings

try:  # pragma: no cover
    from django import conf
    from django.conf import settings as django_settings

    django_installed = True
except ImportError:  # pragma: no cover
    django_installed = False


def load(django_settings_module_name=None, **kwargs):  # pragma: no cover
    if not django_installed:
        raise RuntimeError(
            "To use this extension django must be installed "
            "install it with: pip install django"
        )

    try:
        django_settings_module = sys.modules[django_settings_module_name]
    except KeyError:
        django_settings_module = sys.modules[
            os.environ["DJANGO_SETTINGS_MODULE"]
        ]

    settings_module_name = django_settings_module.__name__
    settings_file = os.path.abspath(django_settings_module.__file__)
    _root_path = os.path.dirname(settings_file)

    # 1) Create the lazy settings object reusing settings_module consts
    options = {
        k.upper(): v
        for k, v in django_settings_module.__dict__.items()
        if k.isupper()
    }
    options.update(kwargs)
    options.setdefault(
        "SKIP_FILES_FOR_DYNACONF", [settings_file, "dynaconf_merge"]
    )
    options.setdefault("ROOT_PATH_FOR_DYNACONF", _root_path)
    options.setdefault("ENVVAR_PREFIX_FOR_DYNACONF", "DJANGO")
    options.setdefault("ENV_SWITCHER_FOR_DYNACONF", "DJANGO_ENV")
    options.setdefault("ENVIRONMENTS_FOR_DYNACONF", True)
    options.setdefault("load_dotenv", True)
    options.setdefault(
        "default_settings_paths", dynaconf.DEFAULT_SETTINGS_FILES
    )
    options.setdefault("_wrapper_class", HookableSettings)

    class UserSettingsHolder(dynaconf.LazySettings):
        _django_override = True

    lazy_settings = dynaconf.LazySettings(**options)
    dynaconf.settings = lazy_settings  # rebind the settings

    # 2) Set all settings back to django_settings_module for 'django check'
    lazy_settings.populate_obj(django_settings_module)

    # 3) Bind `settings` and `DYNACONF`
    setattr(django_settings_module, "settings", lazy_settings)
    setattr(django_settings_module, "DYNACONF", lazy_settings)

    # 4) keep django original settings
    dj = {}
    for key in dir(django_settings):
        if (
            key.isupper()
            and (key != "SETTINGS_MODULE")
            and key not in lazy_settings.store
        ):
            dj[key] = getattr(django_settings, key, None)
        dj["ORIGINAL_SETTINGS_MODULE"] = django_settings.SETTINGS_MODULE

    lazy_settings.update(dj)

    # Allow dynaconf_hooks to be in the same folder as the django.settings
    dynaconf.loaders.execute_hooks(
        "post",
        lazy_settings,
        lazy_settings.current_env,
        modules=[settings_module_name],
        files=[settings_file],
    )
    lazy_settings._loaded_py_modules.insert(0, settings_module_name)

    # 5) Patch django.conf.settings
    class Wrapper:
        # lazy_settings = conf.settings.lazy_settings

        def __getattribute__(self, name):
            if name == "settings":
                return lazy_settings
            if name == "UserSettingsHolder":
                return UserSettingsHolder
            return getattr(conf, name)

    # This implementation is recommended by Guido Van Rossum
    # https://mail.python.org/pipermail/python-ideas/2012-May/014969.html
    sys.modules["django.conf"] = Wrapper()

    # 6) Enable standalone scripts to use Dynaconf
    # This is for when `django.conf.settings` is imported directly
    # on external `scripts` (out of Django's lifetime)
    for stack_item in reversed(inspect.stack()):
        if isinstance(
            stack_item.frame.f_globals.get("settings"), conf.LazySettings
        ):
            stack_item.frame.f_globals["settings"] = lazy_settings

    return lazy_settings


# syntax sugar
DjangoDynaconf = load  # noqa