Django: Global settings variables - django

Suppose I have some global settings for my Django project, stored in a text file for easy editing. I want to load the settings, and then store these variables such that they are accessible from any of my view functions. However, I have read that global variables in Django are discouraged. So, how should I do it? I know how to store these variables in a database, but this seems overkill just for storing a few simple variables.

As alecxe has already pointed out, you can use the settings system. This is the customary way to set values that must be used project-wide. If you read the documentation I've linked too you'll see that they cover very early on that page how to set your own settings.
One thing you must not do when you use Django's settings system is refer to settings at the top level of your modules. For instance if you have a view that does this:
from django.conf import settings
FOO = settings.FOO
(Or alecxe's print statement.) This will prevent values from being overriden. The documentation here goes over the details. I recall having had problems in testing due to this because some of my tests were trying to override the default values, and failed.
The settings system I've mentioned above should be used for values that are meant to be set at start up and not changed afterwards. If you want to record settings that can be changed by the site's administrator at run time, you should use a database of some sort.

Just store your variables in settings.py, this is the best and preferrable way to store your project-specific settings. Then, you can always access them by importing django.conf.settings:
from django.conf import settings
print settings.MY_SETTING
Hope that helps.

Related

Django, separate settings files with a common part

I'm trying to setup Django with two separate settings files, to be selected via the command line parameter --settings, and that (obviously) must have a common file they both use for the common variables.
So I have the file settings_local.py:
DEBUG = True
from . import settings
And I expected that then in settings I would have been able to access DEBUG.
I found no way at all to do that. I've tried to use globals() in both files, I've tried to use global in both, nothing seems to work.
Obviously I cannot import settings_local from settings: the entire point of this setup is to also have a settings_public.py and call either one from the command line. settings itself should be agnostic to it.
I'm also planning to add some kind of control check to ensure settings is not called directly, such as:
try:
DEBUG
except NameError:
raise ValueError( "This file shouldn't be used directly." )
But the exception is always raised, since DEBUG doesn't seem to appear in settings.
I reiterate, even using globals() in both files does not work.
Searched a lot online, couldn't find anything at all that could help me in this very specific situation. I've found many different situations, that either didn't apply, didn't work, or both.
Django settings are just python modules, therefore you cannot write from . import settings and expect settings to have access to global DEBUG variable. Just imagine importing some module which has access to all your global variables - this not only may break module code, but also can lead to bugs in your code relying to these global variables.
The correct answer depends on how complex your requirements are. If you just want to define some variables in dev / prod settings and use them in base settings file the easiest approach would be to switch to .env / .ini / any other external configuration file. E.g. with environ library your code may look like this:
# settings/base.py
import environ
env = environ.Env()
DEBUG = env.bool('DEBUG', default=False)
# now you can use DEBUG value in this file
print(DEBUG)
# settings/local.py
import os
os.environ['DEBUG'] = 'true'
from project.settings.base import *
del os.environ['DEBUG'] # del for simplicity, ideally should be restored to previous value
I'm also planning to add some kind of control check to ensure settings is not called directly
I'm not sure if this is a good idea. What is the reason behind it? If you want to ensure your settings variables are not conflicting with each other it will be better to check their values, without relying on whether the settings module was imported directly or through prod / dev settings. This can be implemented, if you really want to, you'll just need some flag which will indicate if someone imported your base settings outside of dev / prod settings. But this looks like an unnecessary complexity added to the settings module, which should be as simple and dumb as possible

Django: os.environ.get vs import settings

In a views.py would you rather do:
from django.conf import settings
stripe.api_key = settings.STRIPE_SECRET_KEY
or
import os
stripe.api_key = os.environ.get('SECRET_KEY')
Thank you for your help. In my settings I am also using the os.environ.get import.
Settings should only ever change once when the server is started.
If someone were to change your environment whilst still running, then you'd open yourself up to bugs or worse.
When it comes to testing, the second approach would lock you in to an extra requirement of needing to be run in an environment where you have full environment controls, rather than being able to switch the settings file thats being used.
First approach is DRYer, you already state you are setting this in the settings file anyway so theres no need to set the same value to two variables.
tl;dr - Never use the second approach.
You question is a little off. The first option is how you would access the key in your code but does not specify how the key is gotten. What would do is put
import os
stripe.api_key = os.environ.get('SECRET_KEY').
in your settings. You would do this for a couple a reasons, First of all you can but your project on github without anyone seeing your secret key and two if anyone who wasn't supposed to have access to your code does get a hold of it they do not have that information. Basically it is far safer to get the secret key or any key for that matter out of the environment instead of having at in your settings.Then you use option one to access it in the code where it is needed/.

Altering custom settings variable in django at runtime

I have read that settings variable should not be altered at runtime also mentioned here. However if we define a custom settings variable, can it be altered at runtime?
Are there any drawbacks if I do this.
Ex:
settings.CUSTOM_VAR = '20' #done in one of the views
That's not good approach. After you restart or update your server your updated setting will be overwritten for variable that was defined in settings.
You can make own settings model with changeable settings and use it or get some config-apps like django-constance or django-solo or something else and change them legally.

django specific settings app

I am working on a django app that needs a directory to download and store files.
I want to keep my app reusable so I do not want to hard code the path of this directory.
So I want to make this path a setting/a global variable that can be set up.
Where could I put this setting/global variable?
Is this kind of approach good ?
http://blog.muhuk.com/2010/01/26/developing-reusable-django-apps-app-settings.html
Thanks for your advice!
I use the following methodology:
# some file in your app:
from django.conf import settings
MY_APP_SETTING = getattr(settings, 'MY_APP_SETTING', 'some default value')
This effectively allows end-users to customized the setting in their own settings.py, but still ensures that there's always some default value set. You can now use MY_APP_SETTING at will in the rest of your code.
UPDATE
The link in your question was taking too long to load, so I just went ahead and answered. As it turns out, the method I suggested is the same as what it suggests, so yes, I'd consider that approach good ;).

Storing important singular values in Django

So I'm working on a website where there are a couple important values that get used in various places throughout the site. For example, certain important dates, like the start and end dates for registration.
One way I can do this is making a model that stores these values, but that sounds like overkill (since I'd only have one instance). Another way is to store these values in the settings.py file, but if I wanted to change them, it seems like I would need to restart the webserver for them to take effect. I was wondering what would be the best practice in Django to handle this kind of stuff.
You can store them in settings.py. While there is nothing wrong with this (you can even organize your settings into multiple different files, if you have to many custom settings), you're right that you cannot change these at runtime.
We were solving the same problem where I work and came up with a simple app called django-constance (you can get it from github at https://github.com/comoga/django-constance). What this lets is store your settings in a settings.py, but once you need to turn them into settings configurable at runtime, you can switch to a Redis data store with django admin frontend. You can even use the value from settings as your default. I suggest you try this app out.
The changes to your code are pretty minimal, as pasted from docs you initialize your dynamic settings like this:
CONSTANCE_CONFIG = {
'MY_SETTINGS_KEY': (42, 'the answer to everything'),
}
And then instead of importing settings from django conf, you do this:
from constance import config
if config.MY_SETTINGS_KEY == 42:
answer_the_question()
If you want a specific set of variables available to all of your template, what you are looking for is Context Processors.
http://docs.djangoproject.com/en/dev/ref/templates/api/#writing-your-own-context-processors
More links
http://www.b-list.org/weblog/2006/jun/14/django-tips-template-context-processors/
http://blog.madpython.com/2010/04/07/django-context-processors-best-practice/
The code for your context processors, can live anywhere in your project. You just have to add it to your settings.py under:
TEMPLATE_CONTEXT_PROCESSORS =
You could keep the define your constants in your settings.py or even under a constants.py and just
from constants import *
However as you mentioned, you would need to reload your server each time the settings are updated. I think you first need to figure out how often will you be changing these settings? Is it worth the extra effort to be able to reload the settings automatically?
If you wanted to automatically enable the settings, each time they are updated you could do the following:
Store settings in the DB
Upon save/change, write output to a file
settings.py / constants.py reads files
reload server
In addition, you have a look at the mezzanine project which allows you to update settings from the django admin interface and will reload as well.
See: http://mezzanine.jupo.org/docs/configuration.html
If the variables you need will be updated infrequently, i suggest just store them in settings.py and add a custom context processor.
If you are using source control such as GIT, updating will be quite easy, you can just update the file and push to your server. For really simple reloading of the server you could also create a post-recieve hook for git that will automatically reload the server when new code is pushed.
I would only suggest the other option if you are updating settings fairly regularly.