Ways of maintaining separate settings for different environments? - django

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

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

celary.py and wsgi.py: os.environ.get("DJANGO_SETTINGS_MODULE")='proj.settings'

Django 1.11
Celery 4.0.2
Let's read Celery's tutorial:
http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html#index-0
It says that we should place this line in celery.py:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')
Nnamely the documentation says:
You don’t need this line, but it saves you from always passing in the
settings module to the celery program.
I just commented this line out in my IDE. And put a breakpoint after it.
And in the debugger I checked:
os.environ.get("DJANGO_SETTINGS_MODULE")='proj.settings'
Well, the key-value pair is already in the os.environ.
By the way, the same string is in wsgi.py:
os.environ.get("DJANGO_SETTINGS_MODULE")='proj.settings'
It is placed there by django-admin utility when startproject was executed.
So, this doubling the same string is definitely violation of DRY principle.
By the way, settings may be stored not in proj.settings. But in settings.local and settings.production (as Two Scoops of Django recommends).
So, these two strings: in celery.py and wsgi.py are very suspicious.
Could you comment:
1. What do we need them if the value is already mapped to the key in os.environ?
2. How not to violate the DRY principle here especially if we use settings.local and settings.production)?
3. So, what does the Celery's documentation mean by "always passing in the settings module to the celery program"?
What do we need them if the value is already mapped to the key in os.environ?
If its already set in the settings.py you dont need to worry about it for celery again, it's just a practise to remind you that.
How not to violate the DRY principle here especially if we use settings.local and settings.production)?
The common practise if you have settings.local and settings.prod is to include the common settings in settings.base or settings.common. So all the common settings like BASE_DIR etc, will go in there.
So, what does the Celery's documentation mean by "always passing in the settings module to the celery program"?
You should tell celery either to get settings from os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') or app.config_from_object('django.conf:settings', namespace='CELERY').
If you do the one, you can ignore the other, that's what it meant.

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.

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.