Django, separate settings files with a common part - django

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

Related

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

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 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 ;).

Ways of maintaining separate settings for different environments?

My django project has two environments - development and test. Today I carelessly overwrote the settings.py in test with the one in development. It took me a while to correct the settings in test, which could have been avoided if I have a good way to maintain the two sets of settings separately.
I was thinking to keep two separate copies of settings.py and rename/move them when needed. This, however, is kinda caveman approach. Are there any smarter ways of dealing with this problem?
At the end of your settings.py file, add this:
try:
from settings_dev import *
except ImportError: pass
Where settings_dev.py will contain the dev settings. And in your production env, do not push settings_dev (just ignore it in .gitingore or your source code versioning system.)
So, when ever settings_dev.py is present, the settings.py will be overwritten by the settings_dev.py file.
One more approach by setting the environment variable:
if os.environ.get('DEVELOPMENT', None):
from settings_dev import *
mentioned here: Django settings.py for development and production
I prefer the first one, it's simple and just works.
Split your settings as documented here:
https://code.djangoproject.com/wiki/SplitSettings#SimplePackageOrganizationforEnvironments

Django and Eclipse, making a portable project

I like Eclipse for a number of reasons. One of them is, when I'm doing a java project, I can copy and paste my project or rename it, to make a new one, and it will update all the names of everything.
I'm trying to do something similar for a django project.
I can set an APPNAME variable with the following code
APPNAME = os.path.basename(os.path.dirname(__file__))
and then I could import this in any file that needed to know the name of the application. This isn't an ideal solution however but it would work for my settings.py file as well as my urls.py files.
It won't work for situations where I need to import something from somewhere like so:
from myproject.someapp import forms
Is there a way for django/python to know what "myproject" is? Or can I use an import statement relative to the current app?
Or maybe there's a better way to copy django projects.
EDIT: I imagine there are also database dependencies as well that I'd have to deal with.
I follow a couple of rules to keep my applications portable. I'll list them below in the hope that someone finds them useful.
Include my apps in the PYTHONPATH rather than my projects. This way I can execute from app import forms rather than from project.app ....
Following #1, I always import from app only. This means I can reuse my apps in other projects without having to change import statements within the app or in other dependent apps.
If you stick to #1 and #2 you can generally copy and paste projects without too much trouble. You'll still have to modify settings.py though.