django-dynconfig 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. django_dynconfig-0.1.0/LICENSE +21 -0
  2. django_dynconfig-0.1.0/PKG-INFO +190 -0
  3. django_dynconfig-0.1.0/README.md +147 -0
  4. django_dynconfig-0.1.0/pyproject.toml +78 -0
  5. django_dynconfig-0.1.0/setup.cfg +4 -0
  6. django_dynconfig-0.1.0/src/django_dynconfig.egg-info/PKG-INFO +190 -0
  7. django_dynconfig-0.1.0/src/django_dynconfig.egg-info/SOURCES.txt +34 -0
  8. django_dynconfig-0.1.0/src/django_dynconfig.egg-info/dependency_links.txt +1 -0
  9. django_dynconfig-0.1.0/src/django_dynconfig.egg-info/requires.txt +13 -0
  10. django_dynconfig-0.1.0/src/django_dynconfig.egg-info/top_level.txt +1 -0
  11. django_dynconfig-0.1.0/src/dynconfig/__init__.py +32 -0
  12. django_dynconfig-0.1.0/src/dynconfig/admin.py +48 -0
  13. django_dynconfig-0.1.0/src/dynconfig/apps.py +10 -0
  14. django_dynconfig-0.1.0/src/dynconfig/cache.py +56 -0
  15. django_dynconfig-0.1.0/src/dynconfig/checks.py +37 -0
  16. django_dynconfig-0.1.0/src/dynconfig/conf.py +30 -0
  17. django_dynconfig-0.1.0/src/dynconfig/encryption.py +74 -0
  18. django_dynconfig-0.1.0/src/dynconfig/exceptions.py +44 -0
  19. django_dynconfig-0.1.0/src/dynconfig/management/__init__.py +0 -0
  20. django_dynconfig-0.1.0/src/dynconfig/management/commands/__init__.py +0 -0
  21. django_dynconfig-0.1.0/src/dynconfig/management/commands/exportconfigs.py +66 -0
  22. django_dynconfig-0.1.0/src/dynconfig/management/commands/importconfigs.py +97 -0
  23. django_dynconfig-0.1.0/src/dynconfig/migrations/0001_initial.py +93 -0
  24. django_dynconfig-0.1.0/src/dynconfig/migrations/__init__.py +0 -0
  25. django_dynconfig-0.1.0/src/dynconfig/models.py +64 -0
  26. django_dynconfig-0.1.0/src/dynconfig/services.py +164 -0
  27. django_dynconfig-0.1.0/src/dynconfig/signals.py +28 -0
  28. django_dynconfig-0.1.0/src/dynconfig/types.py +86 -0
  29. django_dynconfig-0.1.0/tests/test_admin.py +36 -0
  30. django_dynconfig-0.1.0/tests/test_cache.py +32 -0
  31. django_dynconfig-0.1.0/tests/test_checks.py +26 -0
  32. django_dynconfig-0.1.0/tests/test_commands.py +79 -0
  33. django_dynconfig-0.1.0/tests/test_encryption.py +68 -0
  34. django_dynconfig-0.1.0/tests/test_models.py +38 -0
  35. django_dynconfig-0.1.0/tests/test_services.py +104 -0
  36. django_dynconfig-0.1.0/tests/test_types.py +101 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marcelo Santino
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-dynconfig
3
+ Version: 0.1.0
4
+ Summary: Dynamic configuration management for Django with admin UI, type casting, and optional encryption.
5
+ Author-email: Marcelo Santino <marcelo@santino.dev>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/marcelosantino/django-dynconfig
8
+ Project-URL: Documentation, https://github.com/marcelosantino/django-dynconfig#readme
9
+ Project-URL: Repository, https://github.com/marcelosantino/django-dynconfig
10
+ Project-URL: Changelog, https://github.com/marcelosantino/django-dynconfig/blob/main/CHANGELOG.md
11
+ Project-URL: Issues, https://github.com/marcelosantino/django-dynconfig/issues
12
+ Keywords: django,configuration,settings,dynamic,admin,database
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Web Environment
15
+ Classifier: Framework :: Django
16
+ Classifier: Framework :: Django :: 4.2
17
+ Classifier: Framework :: Django :: 5.0
18
+ Classifier: Framework :: Django :: 5.1
19
+ Classifier: Framework :: Django :: 5.2
20
+ Classifier: Intended Audience :: Developers
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: django>=4.2
32
+ Provides-Extra: encryption
33
+ Requires-Dist: cryptography>=41.0; extra == "encryption"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=8.0; extra == "dev"
36
+ Requires-Dist: pytest-django>=4.8; extra == "dev"
37
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
38
+ Requires-Dist: ruff>=0.4; extra == "dev"
39
+ Requires-Dist: tox>=4.0; extra == "dev"
40
+ Requires-Dist: build>=1.0; extra == "dev"
41
+ Requires-Dist: twine>=5.0; extra == "dev"
42
+ Dynamic: license-file
43
+
44
+ # django-dynconfig
45
+
46
+ [![CI](https://github.com/msantino/django-dynconfig/actions/workflows/ci.yml/badge.svg)](https://github.com/msantino/django-dynconfig/actions/workflows/ci.yml)
47
+ [![PyPI version](https://img.shields.io/pypi/v/django-dynconfig.svg)](https://pypi.org/project/django-dynconfig/)
48
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-dynconfig.svg)](https://pypi.org/project/django-dynconfig/)
49
+ [![Django versions](https://img.shields.io/badge/django-4.2%20|%205.0%20|%205.1%20|%205.2-blue.svg)](https://pypi.org/project/django-dynconfig/)
50
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
51
+
52
+ Dynamic configuration management for Django. Store settings in the database, manage them through the admin, and access them with a simple API. Supports type casting, optional encryption for secrets, and caching.
53
+
54
+ ## Features
55
+
56
+ - **Simple API** — `get_config("key")` from anywhere in your code
57
+ - **Typed values** — Automatic casting to `str`, `int`, `float`, `bool`, `list`, or `json`
58
+ - **Admin UI** — Manage configs in Django admin with grouping, search, and filtering
59
+ - **Optional encryption** — Encrypt sensitive values (API keys, secrets) at rest
60
+ - **Caching** — Uses Django's cache framework with automatic invalidation on save/delete
61
+ - **Import/Export** — Management commands to move configs between environments
62
+
63
+ ## Quick Start
64
+
65
+ ```bash
66
+ pip install django-dynconfig
67
+ ```
68
+
69
+ Add to your `INSTALLED_APPS` and run migrations:
70
+
71
+ ```python
72
+ # settings.py
73
+ INSTALLED_APPS = [
74
+ ...
75
+ "dynconfig",
76
+ ]
77
+ ```
78
+
79
+ ```bash
80
+ python manage.py migrate
81
+ ```
82
+
83
+ That's it. Open the Django admin and start adding configurations, or use the API:
84
+
85
+ ```python
86
+ from dynconfig import get_config, set_config
87
+
88
+ # Set a config (creates it if it doesn't exist)
89
+ set_config("notifications.enabled", True)
90
+ set_config("billing.max_retries", 5)
91
+ set_config("billing.api_key", "sk_live_...", is_encrypted=True, group="billing")
92
+
93
+ # Get a config (typed automatically)
94
+ get_config("notifications.enabled") # → True (bool)
95
+ get_config("billing.max_retries") # → 5 (int)
96
+ get_config("billing.api_key") # → "sk_live_..." (decrypted)
97
+ get_config("missing.key", default=10) # → 10
98
+ ```
99
+
100
+ ## Usage
101
+
102
+ ### Type Casting
103
+
104
+ Values are stored as strings in the database and cast to Python types on retrieval based on the `value_type` field:
105
+
106
+ | value_type | Python type | Example stored | Example returned |
107
+ |------------|-------------|----------------|------------------|
108
+ | `string` | `str` | `"hello"` | `"hello"` |
109
+ | `integer` | `int` | `"42"` | `42` |
110
+ | `float` | `float` | `"3.14"` | `3.14` |
111
+ | `boolean` | `bool` | `"true"` | `True` |
112
+ | `json` | `dict/list` | `'{"a": 1}'` | `{"a": 1}` |
113
+ | `list` | `list` | `"a, b, c"` | `["a", "b", "c"]`|
114
+
115
+ When using `set_config()`, the type is auto-detected from the Python value if not specified.
116
+
117
+ ### Groups
118
+
119
+ Organize configs by group for cleaner admin views:
120
+
121
+ ```python
122
+ set_config("asaas.api_key", "...", group="billing")
123
+ set_config("asaas.webhook_secret", "...", group="billing")
124
+
125
+ # Get all configs in a group
126
+ from dynconfig import get_configs_by_group
127
+ billing = get_configs_by_group("billing")
128
+ # → {"asaas.api_key": "...", "asaas.webhook_secret": "..."}
129
+ ```
130
+
131
+ ### Encryption
132
+
133
+ For sensitive values like API keys and secrets:
134
+
135
+ ```bash
136
+ pip install django-dynconfig[encryption]
137
+ ```
138
+
139
+ ```python
140
+ # settings.py
141
+ DYNCONFIG_ENCRYPTION_KEY = env("DYNCONFIG_ENCRYPTION_KEY")
142
+ ```
143
+
144
+ Generate a key:
145
+
146
+ ```python
147
+ from cryptography.fernet import Fernet
148
+ print(Fernet.generate_key().decode())
149
+ ```
150
+
151
+ Encrypted values are stored as ciphertext in the database and decrypted transparently on read. The admin shows `••••••••` instead of the raw value.
152
+
153
+ ### Management Commands
154
+
155
+ ```bash
156
+ # Export all configs to JSON
157
+ python manage.py exportconfigs -o configs.json
158
+
159
+ # Export only a specific group, excluding secrets
160
+ python manage.py exportconfigs -g billing --no-secrets -o billing.json
161
+
162
+ # Import configs (skip existing by default)
163
+ python manage.py importconfigs configs.json
164
+
165
+ # Import and overwrite existing
166
+ python manage.py importconfigs configs.json --overwrite
167
+
168
+ # Preview without changes
169
+ python manage.py importconfigs configs.json --dry-run
170
+ ```
171
+
172
+ ## Settings
173
+
174
+ All settings are optional with sensible defaults:
175
+
176
+ | Setting | Default | Description |
177
+ |---------|---------|-------------|
178
+ | `DYNCONFIG_CACHE_BACKEND` | `"default"` | Django cache backend to use |
179
+ | `DYNCONFIG_CACHE_TIMEOUT` | `300` | Cache TTL in seconds |
180
+ | `DYNCONFIG_CACHE_PREFIX` | `"dynconfig"` | Cache key prefix |
181
+ | `DYNCONFIG_ENCRYPTION_KEY` | `None` | Fernet key for encryption |
182
+ | `DYNCONFIG_RAISE_NOT_FOUND` | `False` | Raise `ConfigNotFoundError` instead of returning `None` |
183
+
184
+ ## Django System Checks
185
+
186
+ Run `python manage.py check` to verify your configuration. dynconfig will warn you if encrypted config entries exist but `DYNCONFIG_ENCRYPTION_KEY` is not set.
187
+
188
+ ## License
189
+
190
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,147 @@
1
+ # django-dynconfig
2
+
3
+ [![CI](https://github.com/msantino/django-dynconfig/actions/workflows/ci.yml/badge.svg)](https://github.com/msantino/django-dynconfig/actions/workflows/ci.yml)
4
+ [![PyPI version](https://img.shields.io/pypi/v/django-dynconfig.svg)](https://pypi.org/project/django-dynconfig/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-dynconfig.svg)](https://pypi.org/project/django-dynconfig/)
6
+ [![Django versions](https://img.shields.io/badge/django-4.2%20|%205.0%20|%205.1%20|%205.2-blue.svg)](https://pypi.org/project/django-dynconfig/)
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
8
+
9
+ Dynamic configuration management for Django. Store settings in the database, manage them through the admin, and access them with a simple API. Supports type casting, optional encryption for secrets, and caching.
10
+
11
+ ## Features
12
+
13
+ - **Simple API** — `get_config("key")` from anywhere in your code
14
+ - **Typed values** — Automatic casting to `str`, `int`, `float`, `bool`, `list`, or `json`
15
+ - **Admin UI** — Manage configs in Django admin with grouping, search, and filtering
16
+ - **Optional encryption** — Encrypt sensitive values (API keys, secrets) at rest
17
+ - **Caching** — Uses Django's cache framework with automatic invalidation on save/delete
18
+ - **Import/Export** — Management commands to move configs between environments
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ pip install django-dynconfig
24
+ ```
25
+
26
+ Add to your `INSTALLED_APPS` and run migrations:
27
+
28
+ ```python
29
+ # settings.py
30
+ INSTALLED_APPS = [
31
+ ...
32
+ "dynconfig",
33
+ ]
34
+ ```
35
+
36
+ ```bash
37
+ python manage.py migrate
38
+ ```
39
+
40
+ That's it. Open the Django admin and start adding configurations, or use the API:
41
+
42
+ ```python
43
+ from dynconfig import get_config, set_config
44
+
45
+ # Set a config (creates it if it doesn't exist)
46
+ set_config("notifications.enabled", True)
47
+ set_config("billing.max_retries", 5)
48
+ set_config("billing.api_key", "sk_live_...", is_encrypted=True, group="billing")
49
+
50
+ # Get a config (typed automatically)
51
+ get_config("notifications.enabled") # → True (bool)
52
+ get_config("billing.max_retries") # → 5 (int)
53
+ get_config("billing.api_key") # → "sk_live_..." (decrypted)
54
+ get_config("missing.key", default=10) # → 10
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### Type Casting
60
+
61
+ Values are stored as strings in the database and cast to Python types on retrieval based on the `value_type` field:
62
+
63
+ | value_type | Python type | Example stored | Example returned |
64
+ |------------|-------------|----------------|------------------|
65
+ | `string` | `str` | `"hello"` | `"hello"` |
66
+ | `integer` | `int` | `"42"` | `42` |
67
+ | `float` | `float` | `"3.14"` | `3.14` |
68
+ | `boolean` | `bool` | `"true"` | `True` |
69
+ | `json` | `dict/list` | `'{"a": 1}'` | `{"a": 1}` |
70
+ | `list` | `list` | `"a, b, c"` | `["a", "b", "c"]`|
71
+
72
+ When using `set_config()`, the type is auto-detected from the Python value if not specified.
73
+
74
+ ### Groups
75
+
76
+ Organize configs by group for cleaner admin views:
77
+
78
+ ```python
79
+ set_config("asaas.api_key", "...", group="billing")
80
+ set_config("asaas.webhook_secret", "...", group="billing")
81
+
82
+ # Get all configs in a group
83
+ from dynconfig import get_configs_by_group
84
+ billing = get_configs_by_group("billing")
85
+ # → {"asaas.api_key": "...", "asaas.webhook_secret": "..."}
86
+ ```
87
+
88
+ ### Encryption
89
+
90
+ For sensitive values like API keys and secrets:
91
+
92
+ ```bash
93
+ pip install django-dynconfig[encryption]
94
+ ```
95
+
96
+ ```python
97
+ # settings.py
98
+ DYNCONFIG_ENCRYPTION_KEY = env("DYNCONFIG_ENCRYPTION_KEY")
99
+ ```
100
+
101
+ Generate a key:
102
+
103
+ ```python
104
+ from cryptography.fernet import Fernet
105
+ print(Fernet.generate_key().decode())
106
+ ```
107
+
108
+ Encrypted values are stored as ciphertext in the database and decrypted transparently on read. The admin shows `••••••••` instead of the raw value.
109
+
110
+ ### Management Commands
111
+
112
+ ```bash
113
+ # Export all configs to JSON
114
+ python manage.py exportconfigs -o configs.json
115
+
116
+ # Export only a specific group, excluding secrets
117
+ python manage.py exportconfigs -g billing --no-secrets -o billing.json
118
+
119
+ # Import configs (skip existing by default)
120
+ python manage.py importconfigs configs.json
121
+
122
+ # Import and overwrite existing
123
+ python manage.py importconfigs configs.json --overwrite
124
+
125
+ # Preview without changes
126
+ python manage.py importconfigs configs.json --dry-run
127
+ ```
128
+
129
+ ## Settings
130
+
131
+ All settings are optional with sensible defaults:
132
+
133
+ | Setting | Default | Description |
134
+ |---------|---------|-------------|
135
+ | `DYNCONFIG_CACHE_BACKEND` | `"default"` | Django cache backend to use |
136
+ | `DYNCONFIG_CACHE_TIMEOUT` | `300` | Cache TTL in seconds |
137
+ | `DYNCONFIG_CACHE_PREFIX` | `"dynconfig"` | Cache key prefix |
138
+ | `DYNCONFIG_ENCRYPTION_KEY` | `None` | Fernet key for encryption |
139
+ | `DYNCONFIG_RAISE_NOT_FOUND` | `False` | Raise `ConfigNotFoundError` instead of returning `None` |
140
+
141
+ ## Django System Checks
142
+
143
+ Run `python manage.py check` to verify your configuration. dynconfig will warn you if encrypted config entries exist but `DYNCONFIG_ENCRYPTION_KEY` is not set.
144
+
145
+ ## License
146
+
147
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,78 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "django-dynconfig"
7
+ version = "0.1.0"
8
+ description = "Dynamic configuration management for Django with admin UI, type casting, and optional encryption."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Marcelo Santino", email = "marcelo@santino.dev" },
14
+ ]
15
+ keywords = ["django", "configuration", "settings", "dynamic", "admin", "database"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Web Environment",
19
+ "Framework :: Django",
20
+ "Framework :: Django :: 4.2",
21
+ "Framework :: Django :: 5.0",
22
+ "Framework :: Django :: 5.1",
23
+ "Framework :: Django :: 5.2",
24
+ "Intended Audience :: Developers",
25
+
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Programming Language :: Python :: 3.13",
32
+ "Topic :: Software Development :: Libraries :: Python Modules",
33
+ ]
34
+ dependencies = [
35
+ "django>=4.2",
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ encryption = ["cryptography>=41.0"]
40
+ dev = [
41
+ "pytest>=8.0",
42
+ "pytest-django>=4.8",
43
+ "pytest-cov>=5.0",
44
+ "ruff>=0.4",
45
+ "tox>=4.0",
46
+ "build>=1.0",
47
+ "twine>=5.0",
48
+ ]
49
+
50
+ [project.urls]
51
+ Homepage = "https://github.com/marcelosantino/django-dynconfig"
52
+ Documentation = "https://github.com/marcelosantino/django-dynconfig#readme"
53
+ Repository = "https://github.com/marcelosantino/django-dynconfig"
54
+ Changelog = "https://github.com/marcelosantino/django-dynconfig/blob/main/CHANGELOG.md"
55
+ Issues = "https://github.com/marcelosantino/django-dynconfig/issues"
56
+
57
+ [tool.setuptools.packages.find]
58
+ where = ["src"]
59
+
60
+ [tool.ruff]
61
+ target-version = "py310"
62
+ line-length = 120
63
+
64
+ [tool.ruff.lint]
65
+ select = ["E", "F", "I", "N", "W", "UP", "B", "SIM", "DJ"]
66
+
67
+ [tool.pytest.ini_options]
68
+ DJANGO_SETTINGS_MODULE = "tests.settings"
69
+ django_find_project = false
70
+ pythonpath = ["src", "."]
71
+ addopts = "--tb=short -q"
72
+
73
+ [tool.coverage.run]
74
+ source = ["dynconfig"]
75
+
76
+ [tool.coverage.report]
77
+ show_missing = true
78
+ skip_empty = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-dynconfig
3
+ Version: 0.1.0
4
+ Summary: Dynamic configuration management for Django with admin UI, type casting, and optional encryption.
5
+ Author-email: Marcelo Santino <marcelo@santino.dev>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/marcelosantino/django-dynconfig
8
+ Project-URL: Documentation, https://github.com/marcelosantino/django-dynconfig#readme
9
+ Project-URL: Repository, https://github.com/marcelosantino/django-dynconfig
10
+ Project-URL: Changelog, https://github.com/marcelosantino/django-dynconfig/blob/main/CHANGELOG.md
11
+ Project-URL: Issues, https://github.com/marcelosantino/django-dynconfig/issues
12
+ Keywords: django,configuration,settings,dynamic,admin,database
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Web Environment
15
+ Classifier: Framework :: Django
16
+ Classifier: Framework :: Django :: 4.2
17
+ Classifier: Framework :: Django :: 5.0
18
+ Classifier: Framework :: Django :: 5.1
19
+ Classifier: Framework :: Django :: 5.2
20
+ Classifier: Intended Audience :: Developers
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: django>=4.2
32
+ Provides-Extra: encryption
33
+ Requires-Dist: cryptography>=41.0; extra == "encryption"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=8.0; extra == "dev"
36
+ Requires-Dist: pytest-django>=4.8; extra == "dev"
37
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
38
+ Requires-Dist: ruff>=0.4; extra == "dev"
39
+ Requires-Dist: tox>=4.0; extra == "dev"
40
+ Requires-Dist: build>=1.0; extra == "dev"
41
+ Requires-Dist: twine>=5.0; extra == "dev"
42
+ Dynamic: license-file
43
+
44
+ # django-dynconfig
45
+
46
+ [![CI](https://github.com/msantino/django-dynconfig/actions/workflows/ci.yml/badge.svg)](https://github.com/msantino/django-dynconfig/actions/workflows/ci.yml)
47
+ [![PyPI version](https://img.shields.io/pypi/v/django-dynconfig.svg)](https://pypi.org/project/django-dynconfig/)
48
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-dynconfig.svg)](https://pypi.org/project/django-dynconfig/)
49
+ [![Django versions](https://img.shields.io/badge/django-4.2%20|%205.0%20|%205.1%20|%205.2-blue.svg)](https://pypi.org/project/django-dynconfig/)
50
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
51
+
52
+ Dynamic configuration management for Django. Store settings in the database, manage them through the admin, and access them with a simple API. Supports type casting, optional encryption for secrets, and caching.
53
+
54
+ ## Features
55
+
56
+ - **Simple API** — `get_config("key")` from anywhere in your code
57
+ - **Typed values** — Automatic casting to `str`, `int`, `float`, `bool`, `list`, or `json`
58
+ - **Admin UI** — Manage configs in Django admin with grouping, search, and filtering
59
+ - **Optional encryption** — Encrypt sensitive values (API keys, secrets) at rest
60
+ - **Caching** — Uses Django's cache framework with automatic invalidation on save/delete
61
+ - **Import/Export** — Management commands to move configs between environments
62
+
63
+ ## Quick Start
64
+
65
+ ```bash
66
+ pip install django-dynconfig
67
+ ```
68
+
69
+ Add to your `INSTALLED_APPS` and run migrations:
70
+
71
+ ```python
72
+ # settings.py
73
+ INSTALLED_APPS = [
74
+ ...
75
+ "dynconfig",
76
+ ]
77
+ ```
78
+
79
+ ```bash
80
+ python manage.py migrate
81
+ ```
82
+
83
+ That's it. Open the Django admin and start adding configurations, or use the API:
84
+
85
+ ```python
86
+ from dynconfig import get_config, set_config
87
+
88
+ # Set a config (creates it if it doesn't exist)
89
+ set_config("notifications.enabled", True)
90
+ set_config("billing.max_retries", 5)
91
+ set_config("billing.api_key", "sk_live_...", is_encrypted=True, group="billing")
92
+
93
+ # Get a config (typed automatically)
94
+ get_config("notifications.enabled") # → True (bool)
95
+ get_config("billing.max_retries") # → 5 (int)
96
+ get_config("billing.api_key") # → "sk_live_..." (decrypted)
97
+ get_config("missing.key", default=10) # → 10
98
+ ```
99
+
100
+ ## Usage
101
+
102
+ ### Type Casting
103
+
104
+ Values are stored as strings in the database and cast to Python types on retrieval based on the `value_type` field:
105
+
106
+ | value_type | Python type | Example stored | Example returned |
107
+ |------------|-------------|----------------|------------------|
108
+ | `string` | `str` | `"hello"` | `"hello"` |
109
+ | `integer` | `int` | `"42"` | `42` |
110
+ | `float` | `float` | `"3.14"` | `3.14` |
111
+ | `boolean` | `bool` | `"true"` | `True` |
112
+ | `json` | `dict/list` | `'{"a": 1}'` | `{"a": 1}` |
113
+ | `list` | `list` | `"a, b, c"` | `["a", "b", "c"]`|
114
+
115
+ When using `set_config()`, the type is auto-detected from the Python value if not specified.
116
+
117
+ ### Groups
118
+
119
+ Organize configs by group for cleaner admin views:
120
+
121
+ ```python
122
+ set_config("asaas.api_key", "...", group="billing")
123
+ set_config("asaas.webhook_secret", "...", group="billing")
124
+
125
+ # Get all configs in a group
126
+ from dynconfig import get_configs_by_group
127
+ billing = get_configs_by_group("billing")
128
+ # → {"asaas.api_key": "...", "asaas.webhook_secret": "..."}
129
+ ```
130
+
131
+ ### Encryption
132
+
133
+ For sensitive values like API keys and secrets:
134
+
135
+ ```bash
136
+ pip install django-dynconfig[encryption]
137
+ ```
138
+
139
+ ```python
140
+ # settings.py
141
+ DYNCONFIG_ENCRYPTION_KEY = env("DYNCONFIG_ENCRYPTION_KEY")
142
+ ```
143
+
144
+ Generate a key:
145
+
146
+ ```python
147
+ from cryptography.fernet import Fernet
148
+ print(Fernet.generate_key().decode())
149
+ ```
150
+
151
+ Encrypted values are stored as ciphertext in the database and decrypted transparently on read. The admin shows `••••••••` instead of the raw value.
152
+
153
+ ### Management Commands
154
+
155
+ ```bash
156
+ # Export all configs to JSON
157
+ python manage.py exportconfigs -o configs.json
158
+
159
+ # Export only a specific group, excluding secrets
160
+ python manage.py exportconfigs -g billing --no-secrets -o billing.json
161
+
162
+ # Import configs (skip existing by default)
163
+ python manage.py importconfigs configs.json
164
+
165
+ # Import and overwrite existing
166
+ python manage.py importconfigs configs.json --overwrite
167
+
168
+ # Preview without changes
169
+ python manage.py importconfigs configs.json --dry-run
170
+ ```
171
+
172
+ ## Settings
173
+
174
+ All settings are optional with sensible defaults:
175
+
176
+ | Setting | Default | Description |
177
+ |---------|---------|-------------|
178
+ | `DYNCONFIG_CACHE_BACKEND` | `"default"` | Django cache backend to use |
179
+ | `DYNCONFIG_CACHE_TIMEOUT` | `300` | Cache TTL in seconds |
180
+ | `DYNCONFIG_CACHE_PREFIX` | `"dynconfig"` | Cache key prefix |
181
+ | `DYNCONFIG_ENCRYPTION_KEY` | `None` | Fernet key for encryption |
182
+ | `DYNCONFIG_RAISE_NOT_FOUND` | `False` | Raise `ConfigNotFoundError` instead of returning `None` |
183
+
184
+ ## Django System Checks
185
+
186
+ Run `python manage.py check` to verify your configuration. dynconfig will warn you if encrypted config entries exist but `DYNCONFIG_ENCRYPTION_KEY` is not set.
187
+
188
+ ## License
189
+
190
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,34 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/django_dynconfig.egg-info/PKG-INFO
5
+ src/django_dynconfig.egg-info/SOURCES.txt
6
+ src/django_dynconfig.egg-info/dependency_links.txt
7
+ src/django_dynconfig.egg-info/requires.txt
8
+ src/django_dynconfig.egg-info/top_level.txt
9
+ src/dynconfig/__init__.py
10
+ src/dynconfig/admin.py
11
+ src/dynconfig/apps.py
12
+ src/dynconfig/cache.py
13
+ src/dynconfig/checks.py
14
+ src/dynconfig/conf.py
15
+ src/dynconfig/encryption.py
16
+ src/dynconfig/exceptions.py
17
+ src/dynconfig/models.py
18
+ src/dynconfig/services.py
19
+ src/dynconfig/signals.py
20
+ src/dynconfig/types.py
21
+ src/dynconfig/management/__init__.py
22
+ src/dynconfig/management/commands/__init__.py
23
+ src/dynconfig/management/commands/exportconfigs.py
24
+ src/dynconfig/management/commands/importconfigs.py
25
+ src/dynconfig/migrations/0001_initial.py
26
+ src/dynconfig/migrations/__init__.py
27
+ tests/test_admin.py
28
+ tests/test_cache.py
29
+ tests/test_checks.py
30
+ tests/test_commands.py
31
+ tests/test_encryption.py
32
+ tests/test_models.py
33
+ tests/test_services.py
34
+ tests/test_types.py
@@ -0,0 +1,13 @@
1
+ django>=4.2
2
+
3
+ [dev]
4
+ pytest>=8.0
5
+ pytest-django>=4.8
6
+ pytest-cov>=5.0
7
+ ruff>=0.4
8
+ tox>=4.0
9
+ build>=1.0
10
+ twine>=5.0
11
+
12
+ [encryption]
13
+ cryptography>=41.0