Django: os.environ.get vs import settings - django

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/.

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: Global settings variables

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.

Django doesn't read from database – no error

I just set up the environment for an existing Django project, on a new Mac. I know for certain there is nothing wrong with the code itself (just cloned the repo), but for some reason, Django can't seem to retrieve data from the database.
I know the correct tables and data is in the db.
I know the codebase is as it should be.
I can make queries using the Django shell.
Django doesn't throw any errors despite the data missing on the web page.
I realize that it's hard to debug this without further information, but I would really appreciate a finger pointing me to the right direction. I can't seem to find any useful logs.
EDIT:
I just realized the problem lies elsewhere. Unfortunately I can't delete this post with the bounty still open.
Without seeing any code, I can only suggest some general advice that might help you debug your problem. Please add a link to your repository if you can or some snippets of your database settings, the view which includes the database queries etc...
Debugging the view
The first thing I would recommend is using the python debugger inside the view which queries the database. If you've not used pdb before, it's a life saver which allows you to set breakpoints in your Python script and then interactively execute code inside the interpreter
>>> import pdb
>>> pdb.set_trace()
>>> # look at the results of your queries
If you are using the Django ORM, the QuerySet returned from the query should have all the data you expect.
If it doesn't then you need to look into your database configuration in settings.py.
If it does, then you must might not be returning that object to the template? Unlikely as you said the code was the same, but double check the objects you pass with your HttpResponse object.
Debugging the database settings
If you can query the database using the project settings inside settings.py from the django shell it sounds unlikley that there is a problem with this - but like everything double check.
You said that you've set up a new project on a mac. What is on a different operating system before? Maybe there is a problem with the paths now - to make your project platform independent remember to use the os.path.join() method when working with file paths.
And what about the username and password details....
Debugging the template
Maybe your template is referencing the wrong object variable name or object attribute.You mentioned that
Django doesn't throw any errors despite the data missing on the web
page.
This doesn't really tell us much - to quote the Django docs -
If you use a variable that doesn’t exist, the template system will
insert the value of the TEMPLATE_STRING_IF_INVALID setting, which is
set to '' (the empty string) by default.
So to check all the variables available to your template, you could use the debug template tag
{{ debug }}
Probably even better though is to use the django-debugging-toolbar - this will also let you examine the SQL queries your view is making.
Missing Modules
I would expect this to raise an exception if this were the problem, but have you checked that you have the psycopg module on your new machine?

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.