Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it normal to have a settings file for each staging instance/version in a Django project?

Tags:

python

django

Some people use just one settings file for their project. A good alternative is writing modules, replacing the one settings file with a directory with configurations for each specific need:

...    
|    
settings    
|    
|-base.py    
|-local.py    
|-local_alex.py    
|-production.py    
|-staging.py    
|-test.py   

I guess it's normal to have one single settings file for production.

But what happens if I have more staging instances/versions? Let's suppose I have a postgresql DB for each staging instance/environment. Is it ok to have more staging files? Or should I treat the differences between staging versions in another way?

So I could wether have two settings file, one for each staging version or use the same settings file but specify these differences in another way.

What is the recommended approach?

DjangoTwoScoops recommends having more local.py settings files, but no one mentions about several staging files.

Example, I have the production, local and test files. But two staging versions, each with an URL and different database.

DATABASES = {  
    'default': {    
        ...   
        'NAME': 'dbname1',    
        'USER': 'username1',   
       ...    
    }   
}    

and the second one:

DATABASES = {    
    'default': {    
        ...   
        'NAME': 'dbname2',   
        'USER': 'username2',   
       ...     
    }     
}   
like image 770
Alex M.M. Avatar asked Apr 04 '19 09:04

Alex M.M.


2 Answers

It's a good idea to use a base settings file to define common settings which can be overridden by environment variables. So your database settings might look like;

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': os.environ.get('DATABASE_HOST', 'localhost'),
        'PORT': os.environ.get('DATABASE_PORT', '3306'),
        'USER': os.environ.get('DATABASE_USER', 'root'),
        'PASSWORD': os.environ.get('DATABASE_PASSWORD', ''),
        'NAME': os.environ.get('DATABASE_NAME'),
    },
}

The example you've provided is good practice, but I'd avoid specific files for a person, or if you can, specific local settings. Instead look to have environment variables to account for what would otherwise get it's own settings file. That way, it's less code to maintain & easily configured on each server/environment. Each environment your project runs in would define DJANGO_SETTINGS_MODULE in the environment variables to tell django which settings to use.

Use environment specific settings files to inherit the base and then include things like logging and error notifications, if you subscribe to a service like Sentry, which you wouldn't want to be integrated outside of production. So production.py might include additional security settings which you'd want when running in that environment;

DEBUG = False

CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True

SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = False

And if you find that the local settings approach works for you, exclude them from git so that a specific person's settings aren't checked in and if they've got a local database server, they don't need to worry that there password is forever in version control etc.

like image 157
markwalker_ Avatar answered Oct 21 '22 01:10

markwalker_


If you want to have those files tracked via git you don't really have a choice - you put all common settings in one tracked file (settings.py), connection settings for each environment in a different file (settings_prod.py) and then access keys in one untracked (settings_local.py).

But honestly it's not that difficult to make connections work the same way in all environments, so you can put those settings in common file and then only swap untracked file with keys for oauth, etc.

like image 28
Kyryl Havrylenko Avatar answered Oct 21 '22 01:10

Kyryl Havrylenko