django-extra-settings moves runtime options into the admin
:gear: config and manage typed extra settings using just the django admin.
At a glance
- What is it?
- django-extra-settings gives a Django project a database table of typed, admin editable settings that code reads at runtime, so a client can change a feature flag or a label without a redeploy. The trade is that these values become database state, with the caching and startup ordering that implies.
- Who is it for?
- django-extra-settings fits a Django application where operators need to change runtime behaviour without a deploy, where the values belong to the business rather than the deployment, and where an admin who is not a developer has to be able to make those changes safely.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A settings table the admin edits
Django settings live in settings.py, which means changing one is a code change, a commit and a restart. django-extra-settings is a package that offers the alternative: a set of typed extra settings stored in the database and managed entirely through the Django admin, where you can create, update and delete them.
That is the whole product, and it is a small one with a wide use. The topic tags on the project name the use case precisely: admin, conf, config, custom, dynamic, options, preferences, typed. The pyproject keywords also list constance, which points at the family of packages it competes with, though the documentation makes no direct comparison.
The implementation is a normal Django app. The repository layout is conventional, with an extra_settings package, a tests directory, a runtests.py script, tox.ini, requirements-test.txt and a CHANGELOG.md. The package declares no runtime dependencies beyond Django itself, and requirements.txt pins django >= 4.2. The classifiers cover Django 4.2 through 6.1 and Python 3.11 through 3.14, and the project is marked as Development Status 5, Production/Stable. It is MIT licensed.
The last push was on 2026-10-20, and the release history shows 0.15.0 on 2026-07-13, 0.14.1 on 2025-09-04 and 0.14.0 on 2025-04-03, so this is a package with a normal cadence rather than a one off experiment.
Installing it is five steps and one migration
The installation list in the documentation is short enough to reproduce exactly:
- 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.
Two of those steps exist because of how the admin renders, and they are easy to miss. The migrate step creates the settings table, and the collectstatic step is there because the admin forms the package provides carry static assets, presumably icons for the setting types.
The restart step matters more than it looks. Since the values live in the database, the running process has to be able to reach them, and the cache behaviour below determines whether a running process sees a change immediately or only after a cache expiry.
There is no separate settings module to import and no environment variable to set. Adding the app to INSTALLED_APPS is the entire integration for the default case.
Typed values, and an enum you can import anywhere
The settings are typed, which is what separates this from a generic key value table. Each extra setting has a type, and the supported types are exposed as a TextChoices enum in extra_settings.choices rather than as Setting.TYPE_* constants.
That distinction is a practical detail with real consequences. The documentation points out that, unlike Setting.TYPE_*, the enum can be imported anywhere, including your settings.py, without triggering AppRegistryNotReady. That error is the classic Django failure when you touch a model-backed constant during app loading, and avoiding it means you can list your default settings in settings.py without breaking startup:
from extra_settings.choices import SettingType
SettingType.STRING # == "string"The listed types include BOOL, DATE, DATETIME, DECIMAL, DURATION, EMAIL, FILE and more, with the list continuing beyond what the documentation excerpt shows.
Defaults are declared as a list of dictionaries, each item needing a name, a type and a value:
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",
},
# ...
]And all of the package's own settings are optional, with the documented default values applying when they are absent from settings.py.
The settings that control the settings
The package exposes ten configuration keys, and a few of them change behaviour in ways that are easy to get wrong.
EXTRA_SETTINGS_ADMIN_APP defaults to extra_settings and names the installed app whose admin group holds the settings model admin. EXTRA_SETTINGS_CACHE_NAME defaults to extra_settings and names the cache to use, falling back to the default cache when that name is not found in settings.CACHES. EXTRA_SETTINGS_VERBOSE_NAME defaults to Settings and is the package name displayed in the admin.
Two keys are about names rather than storage. EXTRA_SETTINGS_ENFORCE_UPPERCASE_SETTINGS, defaulting to True, forces setting names to honour the standard Django settings format. EXTRA_SETTINGS_FALLBACK_TO_CONF_SETTINGS, also defaulting to True, makes the template tag fall back to django.conf.settings, which the documentation calls very useful for retrieving conf settings such as DEBUG.
Two keys set upload paths for the file and image types, EXTRA_SETTINGS_FILE_UPLOAD_TO defaulting to files and EXTRA_SETTINGS_IMAGE_UPLOAD_TO defaulting to images, and two keys control the admin changelist, EXTRA_SETTINGS_SHOW_NAME_PREFIX_LIST_FILTER and EXTRA_SETTINGS_SHOW_TYPE_LIST_FILTER, both defaulting to False.
The upload path keys are the ones to think about. A setting of type file or image stores a reference to an uploaded object, which means the admin form is accepting uploads for values that end up in a configuration table. That is worth a deliberate decision about storage and access rather than a default you inherit.
Caching is what makes a database backed setting fast
A settings table queried on every request would be a performance problem, so the package caches values. The documentation says the app caching options are customised with the settings.CACHES["extra_settings"] setting, otherwise the default cache is used:
CACHES = {
# ...
"extra_settings": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"TIMEOUT": 60,
},
# ...
}Note that the default is the extra_settings cache, and if you want a different one you set it with the EXTRA_SETTINGS_CACHE_NAME setting.
The LocMemCache example in the documentation is worth pausing on. LocMem stores values in the memory of the process that wrote them, which means each application server process has its own cache and its own view of the settings. In a multi process or multi machine deployment, a change made in the admin will not be visible to the other workers until their cache entries expire and each one reads the new value. That is a coherent design for a cache, and it is also a deployment property you inherit without being told, so it belongs in your decision.
A shared cache backend, such as a memcached or Redis backed one, changes the propagation story. The documentation does not describe an invalidation mechanism for either case, so what the TIMEOUT value means in practice, and whether an admin save clears the cache, is not stated and would need checking against the source.
Registering the admin in more than one app
By default the extra_settings app has its own admin app group, and the settings model admin appears there. The documentation then offers two extensions for teams who want the settings to live next to the app they belong to.
The first is the EXTRA_SETTINGS_ADMIN_APP setting, which displays the settings model admin in another installed app group. The second is more advanced control: registering the settings admin with multiple installed apps and filtering each app's settings using the queryset_processor argument, done through the register_extra_settings_admin function from extra_settings.admin:
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,
)The second example in the documentation does the same for a videos app, filtering on a different name prefix. The mechanism is name prefix based, which means it leans on the convention enforced by EXTRA_SETTINGS_ENFORCE_UPPERCASE_SETTINGS. If you turn that enforcement off and use names without prefixes, the filters have nothing to match on.
There is a cost to this, and the documentation warns about it in bold. If you register the admin in another app or in several apps, you must run migrations for each of those apps, because Django creates migrations even for proxy models. That is a deployment step that people forget and then debug as a missing admin entry.
Celery autodiscovery can break the defaults
There is one warning in the documentation that deserves to be read as a known bug rather than a footnote.
The warning concerns Celery's autodiscover_tasks with force=True. According to the documentation, it triggers an aggressive task discovery that accesses Django settings before they are fully initialized, and this premature access prevents django-extra-settings from properly setting up its default configuration values. The documentation links to issue 177 in the project for more information.
The mechanism is plausible and specific: the app has to read its own configuration, including EXTRA_SETTINGS_DEFAULTS, at startup, and anything that touches Django settings before initialization completes can arrive too early. The result is not a crash so much as a project whose defaults were not applied, which is the harder failure to notice.
If your project uses Celery with forced autodiscovery, this is the single thing to check before adopting the package, because the symptom is a missing or partial set of default settings rather than an error message naming the cause. The documentation does not describe a workaround, only the warning and the issue link.
Where a database backed settings table is the wrong answer
Three cases argue against this approach.
The first is secrets and connection strings. A password stored in a table readable and writable through the admin is a different security posture from a password in an environment variable or a secret manager, and no amount of typed validation changes the fact that the admin is a web surface. The package does not claim to be a secrets store, and it should not be used as one.
The second is atomicity with code. A Django settings value and the code that reads it are usually changed together. If the setting lives in the database, a deployment that changes behaviour and a database row that changes behaviour are two separate operations that can be applied in either order, and there is a window where the code and the configuration disagree. For a flag that turns a feature on, that window can be the whole rollout.
The third is testing and review. A value in settings.py is version controlled, reviewed and diffed. A value in a table is none of those things, so the usual questions about who changed it and when have to be answered by an audit trail you build yourself.
The alternative approach is to keep the values in Django settings and manage the environment that supplies them, which keeps one source of truth and one deployment step. Where you want non developer editing, a settings table is the trade, and the trade is worth it only if the settings genuinely need to change more often than the code does.
On the software side, the package itself is small, MIT licensed, has no dependencies beyond Django, and is actively worked on. The risk in adopting it is not the library, it is the operational model of storing configuration in a database.
Editorial conclusion
django-extra-settings fits a Django application where operators need to change runtime behaviour without a deploy, where the values belong to the business rather than the deployment, and where an admin who is not a developer has to be able to make those changes safely. It is the wrong choice for values that belong in version control, such as secrets, database URLs and feature switches that should change atomically with code, and it is the wrong choice for a project that cannot tolerate a settings table becoming a second source of truth. Before adopting it, check three things: how the template tag resolves a value when the database is unavailable, since the fallback to django.conf.settings exists but its exact behaviour is not described in the documentation, which cache backends you have configured for the extra_settings alias, and whether your Celery setup uses autodiscover_tasks with force=True, which the documentation warns triggers task discovery before settings are fully initialized and prevents the default configuration from being set up.
Frequently asked questions
How do I install django-extra-settings?
Run pip install django-extra-settings, add extra_settings to settings.INSTALLED_APPS, then run python manage.py migrate and python manage.py collectstatic, and restart the application server. The settings can then be created, updated and deleted in the Django admin.
How do I define default values for extra settings?
Set EXTRA_SETTINGS_DEFAULTS to a list of dictionaries, where each item contains a name, a type and a value. The types come from the SettingType enum in extra_settings.choices, for example SettingType.STRING, which can be imported into settings.py without triggering AppRegistryNotReady.
Which Django versions does django-extra-settings support?
The packaging metadata lists Django 4.2, 5.0, 5.1, 5.2, 6.0 and 6.1, with Python 3.11 through 3.14, and requires-python of 3.11 or newer. requirements.txt pins django >= 4.2.
Does django-extra-settings work with Celery?
There is a documented warning: using Celery's autodiscover_tasks with force=True triggers task discovery that accesses Django settings before they are fully initialized, which prevents the package from setting up its default configuration values. The documentation links to issue 177 for details.
Can I show the extra settings admin inside another Django app?
Yes. Set EXTRA_SETTINGS_ADMIN_APP to the app name, or use register_extra_settings_admin from extra_settings.admin with a queryset_processor filter for finer control. In both cases you must run migrations for each app that displays the admin, because Django creates migrations even for proxy models.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/fabiocaccamo-django-extra-settings)Was this useful?