[![](https://img.shields.io/pypi/pyversions/django-extra-settings.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/) [![](https://img.shields.io/pypi/djversions/django-extra-settings?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/) [![](https://img.shields.io/pypi/v/django-extra-settings.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-extra-settings/) [![](https://static.pepy.tech/badge/django-extra-settings/month)](https://pepy.tech/project/django-extra-settings) [![](https://img.shields.io/github/stars/fabiocaccamo/django-extra-settings?logo=github&style=flat)](https://github.com/fabiocaccamo/django-extra-settings/stargazers) [![](https://img.shields.io/pypi/l/django-extra-settings.svg?color=blue)](https://github.com/fabiocaccamo/django-extra-settings/blob/main/LICENSE.txt) [![](https://results.pre-commit.ci/badge/github/fabiocaccamo/django-extra-settings/main.svg)](https://results.pre-commit.ci/latest/github/fabiocaccamo/django-extra-settings/main) [![](https://img.shields.io/github/actions/workflow/status/fabiocaccamo/django-extra-settings/test-package.yml?branch=main&label=build&logo=github)](https://github.com/fabiocaccamo/django-extra-settings) [![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-extra-settings?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-extra-settings) [![](https://img.shields.io/codacy/grade/554c0505ed9844f3865bee975d1b894c?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-extra-settings) [![](https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=black)](https://github.com/psf/black) [![](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/fabiocaccamo/django-extra-settings/badge)](https://securityscorecards.dev/viewer/?uri=github.com/fabiocaccamo/django-extra-settings) # django-extra-settings config and manage typed extra settings using just the django admin. ![](https://user-images.githubusercontent.com/1035294/74425761-81325400-4e54-11ea-9095-3d64e1420bfe.gif) ## Installation - Run `pip install django-extra-settings` - Add `extra_settings` to `settings.INSTALLED_APPS` - Run `python manage.py migrate` - Run `python manage.py collectstatic` - Restart your application server - Just go to the admin where you can `create`, `update` and `delete` your settings. ## Usage ### Settings All these settings are optional, if not defined in `settings.py` the default values (listed below) will be used. ```python # the name of the installed app for registering the extra settings admin. EXTRA_SETTINGS_ADMIN_APP = "extra_settings" ``` ```python # the name of the cache to use, if not found the "default" cache will be used. EXTRA_SETTINGS_CACHE_NAME = "extra_settings" ``` ```python from extra_settings.choices import SettingType # a list of settings that will be available by default, each item must contain "name", "type" and "value". # check the #types section to see all the supported settings types. EXTRA_SETTINGS_DEFAULTS = [ { "name": "SETTING_NAME", "type": SettingType.STRING, "value": "Hello World", }, # ... ] ``` ```python # if True, settings names will be forced to honor the standard django settings format EXTRA_SETTINGS_ENFORCE_UPPERCASE_SETTINGS = True ``` ```python # if True, the template tag will fallback to django.conf.settings, # very useful to retrieve conf settings such as DEBUG. EXTRA_SETTINGS_FALLBACK_TO_CONF_SETTINGS = True ``` ```python # the upload_to path value of settings of type 'file' EXTRA_SETTINGS_FILE_UPLOAD_TO = "files" ``` ```python # the upload_to path value of settings of type 'image' EXTRA_SETTINGS_IMAGE_UPLOAD_TO = "images" ``` ```python # if True, settings name prefix list filter will be shown in the admin changelist EXTRA_SETTINGS_SHOW_NAME_PREFIX_LIST_FILTER = False ``` ```python # if True, settings type list filter will be shown in the admin changelist EXTRA_SETTINGS_SHOW_TYPE_LIST_FILTER = False ``` ```python # the package name displayed in the admin EXTRA_SETTINGS_VERBOSE_NAME = "Settings" ``` ### Celery > [!WARNING] > When using **Celery**'s `autodiscover_tasks` with `force=True`, it triggers an aggressive task discovery that accesses Django settings before they're fully initialized. This premature access prevents `django-extra-settings` from properly setting up its default configuration values. More info [here](https://github.com/fabiocaccamo/django-extra-settings/issues/177). ### Admin You can display the settings model admin in another installed app group by using the `EXTRA_SETTINGS_ADMIN_APP` setting. You can also have a more advanced control, by registering the settings admin with multiple installed apps and filtering each app settings using the `queryset_processor` argument. > :warning: If you do either of the above, you must run migrations for each app that will display `extra_settings` model admin in its admin *(because django creates migrations even for proxy models)*. #### Admin advanced configuration example In your custom app `photos.admin` module: ```python from extra_settings.admin import register_extra_settings_admin register_extra_settings_admin( app=__name__, queryset_processor=lambda qs: qs.filter(name__istartswith="PHOTOS_"), unregister_default=True, ) ``` In your custom app `videos.admin` module: ```python from extra_settings.admin import register_extra_settings_admin register_extra_settings_admin( app=__name__, queryset_processor=lambda qs: qs.filter(name__istartswith="VIDEOS_"), unregister_default=True, ) ``` By default the `"extra_settings"` app has its own admin app group. ### Caching You can customise the app caching options using `settings.CACHES["extra_settings"]` setting, otherwise the `"default"` cache will be used: ```python CACHES = { # ... "extra_settings": { "BACKEND": "django.core.cache.backends.locmem.LocMemCache", "TIMEOUT": 60, }, # ... } ``` By default the `"extra_settings"` cache is used, if you want to use another cache you can set it using the `EXTRA_SETTINGS_CACHE_NAME` setting. ### Python You can **create**, **read**, **update** and **delete** settings programmatically: #### Types Setting types are available as a `TextChoices` enum in `extra_settings.choices`. Unlike `Setting.TYPE_*`, it can be imported anywhere (including your `settings.py`) without triggering `AppRegistryNotReady`: ```python from extra_settings.choices import SettingType SettingType.STRING # == "string" ``` This is the list of the currently supported setting types: - `SettingType.BOOL` - `SettingType.DATE` - `SettingType.DATETIME` - `SettingType.DECIMAL` - `SettingType.DURATION` - `SettingType.EMAIL` - `SettingType.FILE` - `SettingType.FLOAT` - `SettingType.IMAGE` - `SettingType.INT` - `SettingType.JSON` - `SettingType.STRING` - `SettingType.TEXT` - `SettingType.TIME` - `SettingType.URL` > The `Setting.TYPE_*` constants (e.g. `Setting.TYPE_STRING`) remain available as > aliases for backward compatibility. #### Create ```python from extra_settings.models import Setting setting_obj = Setting( name="SETTING_NAME", value_type=Setting.TYPE_STRING, value="django-extra-settings", ) setting_obj.save() ``` #### Read ```python from extra_settings.models import Setting value = Setting.get("SETTING_NAME", default="django-extra-settings") ``` #### Update ```python from extra_settings.models import Setting setting_obj = Setting( name="SETTING_NAME", value_type=Setting.TYPE_BOOL, value=True, ) setting_obj.value = False setting_obj.save() ``` #### Delete ```python from extra_settings.models import Setting Setting.objects.filter(name="SETTING_NAME").delete() ``` #### Validators You can define a custom validator for each setting: - Validators must be defined using full python path, eg. `myapp.mymodule.my_validator`. - Validators are called passing a single argument (the value of the setting) and if the value is valid, they should return `True`, otherwise returning `False` or `None` a `ValidationError` is raised. ### Templates You can retrieve settings in templates: ```html {% load extra_settings %} {% get_setting 'SETTING_NAME' default='django-extra-settings' %} ``` ### Tests You can override specific settings during tests using `extra_settings.test.override_settings`. It can be used both as decorator and as context-manager: ```python from extra_settings.test import override_settings # decorator @override_settings(SETTING_NAME_1="value for testing 1", SETTING_NAME_2="value for testing 2") def test_with_custom_settings(self): pass # context manager def test_with_custom_settings(self): with override_settings(SETTING_NAME_1="value for testing 1", SETTING_NAME_2="value for testing 2"): pass ``` ## Testing ```bash # clone repository git clone https://github.com/fabiocaccamo/django-extra-settings.git && cd django-extra-settings # create virtualenv and activate it python -m venv venv && . venv/bin/activate # upgrade pip python -m pip install --upgrade pip # install requirements pip install -r requirements.txt -r requirements-test.txt # install pre-commit to run formatters and linters pre-commit install --install-hooks # run tests tox # or python runtests.py # or python -m django test --settings "tests.settings" ``` ## License Released under [MIT License](LICENSE.txt). --- ## Supporting - :star: Star this project on [GitHub](https://github.com/fabiocaccamo/django-extra-settings) - :octocat: Follow me on [GitHub](https://github.com/fabiocaccamo) - :blue_heart: Follow me on [Bluesky](https://bsky.app/profile/fabiocaccamo.bsky.social) - :moneybag: Sponsor me on [Github](https://github.com/sponsors/fabiocaccamo) ## See also - [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. ๐Ÿง™ โšก - [`django-cache-cleaner`](https://github.com/fabiocaccamo/django-cache-cleaner) - clear the entire cache or individual caches easily using the admin panel or management command. ๐Ÿงนโœจ - [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. ๐ŸŽจ - [`django-email-validators`](https://github.com/fabiocaccamo/django-email-validators) - no more invalid or disposable emails in your database. โœ‰๏ธ โœ… - [`django-maintenance-mode`](https://github.com/fabiocaccamo/django-maintenance-mode) - shows a 503 error page when maintenance-mode is on. ๐Ÿšง ๐Ÿ› ๏ธ - [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. โ†ช๏ธ - [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. ๐ŸŒณ - [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. ๐Ÿ“˜ - [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. ๐Ÿ‡ฎ๐Ÿ‡น ๐Ÿ’ณ - [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - friendly font operations. ๐Ÿงข - [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. ๐ŸงŸโ€โ™‚๏ธ