-
-
Notifications
You must be signed in to change notification settings - Fork 287
/
django_dynaconf_v2.py
142 lines (112 loc) · 4.49 KB
/
django_dynaconf_v2.py
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
"""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
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
)
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