Changing Django settings at runtime
Asked Answered
G

10

74

I'd like to expose some (app-specific) settings to the admin interface, so users can change them comfortably and also not have to restart Django.

How should I go about this?

I checked out the applications on http://djangopackages.com/grids/g/live-setting/ (btw django-constance was the most appealing) but really what all these apps are doing is storing values in a database, providing a web interface to change them, and caching. Aren't the first two features already built into Django?

The biggest drawbacks I see are that none of the apps are drop-in replacements for the old location of these settings (settings.py), and require me to migrate to their notation, and often add another context processor to access them in templates.

Couldn't I just do this?

  1. Create a model for my settings (this gives me the various types and validation)
  2. Instantiate one such object to hold my settings (this allows the users to edit them in the admin interface) - I could dump defaults as fixtures like for other models
  3. Wrap settings.py so it makes a database query for my settings - http://www.loose-bits.com/2011/04/extending-django-settings-with-derived.html

From my current, naive point of view the only drawbacks I see would be:

  1. Adding or changing the available settings requires a schema migration (south). - I can live with that.
  2. I have a model with possibly multiple instances but really only need a singleton. - That could actually be a useful feature at some point.
  3. Performance/Caching: Looking at http://code.djangoproject.com/svn/django/trunk/django/conf/ I'd have to put a little bit of cleverness into the settings wrapper and/or model, so that model changes clear or update cached values. - doesn't seem to be rocket science.
  4. Doing the same in another project would require a similar effort again. - I think a single dictionary constant in settings.py, holding model name(s) and field names for the lookups is all that would differ.

Wouldn't this be the best of both worlds - runtime admin (with all its perks), database backend, caching, and none of my settings.USED_TO_BE_IN_SETTINGS_DOT_PY would need any changing. Am I missing something?

Gaekwar answered 30/6, 2011 at 0:17 Comment(11)
If you want to use django.conf.settings like you are used there is no way you can achieve what you want, except hacking Django itself. You should migrate your call to settings at least (code migration) to use the settings object provided by the external library.Idzik
Thanks for your comment. Using a settings.py wrapper (see URL please) is not hacking Django itself imho, just the way that settings.py will return settings from the project (however they are then handled). Adding another app and rewriting all imports seems more work than my approach, and I'm wondering why this approach would not be sufficient or not do what I'm currently predicting...Gaekwar
Maybe I misunderstand you, but is the example wrapper not the same and you still have to rewrite your imports to settings? I wrote such an app a little time ago (company internal, so I am sadly not allowed to release it yet), which write a wrapper around settings. Instead of from django.conf import settings it would then be from my_settings_app import settings in my apps which are using it. In this case the last is access the db/cache and fallback to default settings if both of them not exist. Is that not what you mean?Idzik
That is what I mean but I don't yet see why I can't do the same with settings.py itself - it's a python module.Gaekwar
You mean your project settings? Yes, of course you can do it, though you still need to change your imports. If you still do from django.conf import settings it will have the same effect as before, meaning importing the settings objects from django/conf/__init__.py, which is also just a wrapper around you project settings file. It is not intended to wrap another Object according to code. Again: except you hack into Django itself.Idzik
siteconfig in djblets just monkeypatches settings - done once in the beginning, and then whenever a value changes: github.com/djblets/djblets/blob/master/djblets/siteconfig/… (chipx86.com/blog/2008/08/05/…) - is that not feasible?Gaekwar
Sure that works somehow. I would not suggest this way though either, since you have to be sure all modules using django settings are imported (reloaded) each time the values in settings are changed (to use the new settings). Once your project gets bigger it will be pain to do this.Idzik
I believe if the imports are exactly the same (from django.conf import settings) they will be sharing the same object, and re-importing therefore not necessary. Still, I agree that's getting a bit too much magic. A separate container for runtime settings it is (django-constance seems most fitting for my purposes). I wish Django had built-in support for (potentially) dynamic settings (per Site), and a clear separation from immutable "server settings". The documentation of which (see my comment to André's answer) would be a first step I guess. So... this sort of answers my question :-)Gaekwar
(For future reference) The url in the question is not working anymore, but a working (as of now) URL is djangopackages.com/grids/g/live-settingClamor
Someone released this today: github.com/amdorra/django-kvmodelGaekwar
Does anyone have any solution for the Admin and Manager manipulation for settings?Legislature
F
30

AFAIK, the Django settings are supposed to be immutable. There are multiple reasons for this, the most obvious being that Django is not aware of the server's execution model (prefork / multi-threaded).

Also, you can't load the settings themselves from a Django model because the settings need to be loaded before you can use anything in the ORM.

So, basically, you have two solutions:

  • you can bootstrap the settings from the database by using any lower-level database access mechanism to load them; or
  • you can just define your settings in some other model and fetch them directly when you need them.

The first is an incredible hack and I don't suggest it. The second is much more direct and cleaner, but requires you to change your usual habits (from django.conf import settings).

The second approach is probably what's implemented by the 3rd-party apps you linked to.

Fribble answered 30/6, 2011 at 0:28 Comment(2)
Thanks for your comment. Some Django settings can be changed at runtime although it's currently undocumented which - code.djangoproject.com/ticket/14628 - I meant truly app-specific settings (think business policies, percentages, dates etc. used for calculations). I only want to factor out those ones. The idea of the wrapper I mentioned is that django.conf.settings can still be used although the values are in the database.Gaekwar
Hi, I am pretty late to the party. But is there any way, that I can change one particular variable of settings for admin module. Means I want that when I open admin module, the variable should be 'true' and otherwise 'false'Derouen
B
16

From Django 1.8 docs:

You shouldn’t alter settings in your applications at runtime.

Bug answered 11/5, 2016 at 12:13 Comment(1)
Thanks Chuck, please see my comment to André Caron's answer. The docs have stated that for years code.djangoproject.com/ticket/14628 - also in my case (question posted five years ago) I meant my own app-specific settings, not Django built-in settings.Gaekwar
D
12

DATABASES is a dict. So you can manipulate how a dictionary:

import django.conf as conf

conf.settings.DATABASES['default']['NAME'] = 'novo_banco'
Demodulator answered 1/3, 2013 at 20:1 Comment(4)
The problem is at what time does Django read this to create django.db.connections. Because after that you will end up out of sync with the ORM.Unprincipled
This olny allows me edit in execution time, not persistently. When I restart the service, the value returns to the old.Paisano
This is NOT recommended. You can, in Python, but should not, in Django. Python allows you to do things like as accessing "__foo" methods which are intended to be "private". You can, but it's not good and your code will break somedays. Django settings are thought to be immutable.Virtues
It is doesn't work~! I am still Finding another option!Insomuch
E
2

Take a look: https://bitbucket.org/bkroeze/django-livesettings *Django-Livesettings is a project split from the Satchmo Project_. It provides the ability to configure settings via an admin interface, rather than by editing "settings.py".*

Maybe it can be helpful for you.

Eridanus answered 21/12, 2012 at 13:50 Comment(1)
Have a look djangopackages.org/grids/g/live-setting linked in the OP's question, it lists all the Django packages that do this functionality.Germanism
A
2

Honestly I get more Django when I analyze his code. In version 1.4.5 did it (following the module below):

  • myproject\manage.py

  • django\core\management__init__.py ## method - execute_manager

  • django\conf__init__.py ## class - LazySettings; attr - _wrapped

  • django\utils\functional.py ## class LazyObject; important method - new_method_proxy

Functional option, but it has its risks. In the python "_" considers the attribute as protected.

from django.conf import settings

settings._wrapped.INSTALLED_APPS = () ## *really work*

In the following project: https://github.com/alexsilva/DJPlugins you can see this variable being modified at runtime. the idea of the project is already working.

Atalie answered 30/5, 2013 at 6:1 Comment(2)
changing a global variable (as the case of settings) will be good for single process, but will not be good enough if you are running a production environment with multiple workers (each with its own copy of global variables)Frivolity
It helps me with test where I needed delete attribute to check if missing raise will show, thanks!Archicarp
I
0

You cannot directly modify the settings.py file For example: If u want change the database at runtime, you should Separate the configuration of the database

# Projecr_name/user_database.py
user_database = {
'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'name',
    'USER': 'admin',
    'PASSWORD': '111111',
    'HOST': '127.0.0.1',
    'PORT': '3306'
},
'user_db': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'user1',
    'USER': 'admin',
    'PASSWORD': '22222',
    'HOST': '127.0.0.1',
    'PORT': '3306'
}
}
# Projecr_name/settings.py
from .user_database import user_database
...
DATABASES = user_database
...

Call in your logical view

# view.py
from ../Projecr_name/user_database import user_database
class Some(...):
    def Some(request):
    user_database['user_db']['NAME']='user2'

then you can change any setting at runtime use this way

Insomuch answered 8/7, 2020 at 12:27 Comment(0)
P
0

If you have a variable in the settings.py and you want it to change at any time there is 2 ways the First one is to make a table in database then make for it a serializer then make a view set and any time you want to get it you could send a http request to this viewset then retrieve the data Second one is to use caching it is so fast and it is familiar to localStorage in angular

Precambrian answered 24/7, 2022 at 20:20 Comment(0)
D
0

export DJANGO_SETTINGS_MODULE=mysite.settings You might have set DJANGO_SETTINGS_MODULE in environment variables.

Derogatory answered 19/6 at 9:10 Comment(0)
W
-1

On user operation write the settings to a python file like:

`CONFIG_FILE_PATH = os.path.join(BASE_DIR, 'config', "db_config.py")

with open(CONFIG_FILE_PATH, 'w') as fp: db_data = json.dumps(db_config, indent=4) db_str = f"DATABASE_CONFIG = {db_data}" fp.write(db_str)`

Then import this python file into settings.py Whenever there is a change in db_config.py, settings will be reloaded.

Windbag answered 22/12, 2023 at 11:54 Comment(0)
B
-2

You can use recomended .configure() method of settings module:

from django.conf import settings
settings.configure(DEBUG=True)

settings module has additional handy features. Check docs.

Banter answered 19/12, 2018 at 8:14 Comment(2)
This launches raise RuntimeError('Settings already configured.')Skipp
Same raise RuntimeError('Settings already configured.')Insomuch

© 2022 - 2024 — McMap. All rights reserved.