Django

Setting Up Django Project with Production Environment

In this tutorial I'll be showing you guys how to modify your project structure so that it best fits the production environment and you can be more productive in developing once all the workflow is setup.

So starting with what do I mean by production environment is that assuming you website is deployed on production and it is connected to a production database and its DEBUG setting is False (according to django's official documentation this step is compulsory for production environments)

Now if you are working with only 1 settings.py file you need to replace the database credentials with your local database because obviously you don't want to work on production database on local and set DEBUG to True so that you can easily debug the app on local now whenever you want to deploy the app you need to change these settings back to work on production which is not optimal solution. so here are couple of solutions I propose

1.Use Environment Variables:

One way is that we use environment variables and store this information there both on local and production and in settings file we import the variables and use them so that we dont have to bother about changing them like
on local you can do

export SECRET_KEY=12edh1278h23981h31j3h128371h312i

export DEBUG=True

then these variables can be used in settings.py file like

import os
DEBUG = os.environ.get('DEBUG', False)
SECRET_KEY = os.environ.get('SECRET_KEY', '')

similarly we can do it for database as well

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USERNAME'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOSTNAME'],
'PORT': os.environ['DB_PORT'],
}
}

but there are some settings which we cant to just be implement on the local but we don't want those settings to be implemented on production and these settings are not just values which can be stored in environment and used in local and production environment.

for example, you want to have extra apps on local like django-debug-toolbar which is for debugging on local you don't want it on production now its not like a value that you can store in variable and that can cause a difference on local and production. Is there ??


Actually there are ways one can suggest maybe why don't you do something like this

For local

export ENV_TYPE='local'

For production

export ENV_TYPE='production'
if os.environ.get('ENV_TYPE', 'local') == 'local':
"""ALL of your local specific settings here"""
INSTALLED_APPS += [ 'django-debug-toolbar' ]
elif os.environ.get('ENV_TYPE', 'local') == 'production':
"""ALL of your local specific settings here"""
pass

well, this type of thing can work but I don't recommend it. couple of reasons..

  1. we want our settings file to be short and easy to work with whereas this method is doing the opposite.
  2. This can get real messy when we have multiple environments like, local, staging, production maybe separate settings for docker environment etc

What I recommend is that we go with separate files for separate type or settings something like

mysite/settings
├── __init__.py
├── base.py
├── local.py
├── production.py
└── staging.py

removing settings.py file and creating a settings directory instead having multiple file

  1. base.py (containing common settings among all environments)
  2. local.py (settings specific to local environment)
  3. production.py
  4. staging.py
  5. __init__.py (this file is necessary to keep the object/instance structure of python)

couple of pointers to keep in mind
1. as now our directory structure has changed like before settings file was 1 step deep into project root directory now its 2 steps deep

mysite> settings.py

mysite > settings > local.py

so some of the code should be changed as well which is dependent on directory structure like BASE_DIR

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

it should now be 1 more step deep

BASE_DIR = os.path.dirname(os.path.dirname(
os.path.dirname(os.path.abspath(__file__))))

so keep in mind this kind of situation where you might be importing some stuff doing

from .tasks import SOMETHING

after changing structure this should change as well to

from mysite.tasks import SOMETHING
or
from ..tasks.py import SOMETHING

this stuff is obvious but just in case 😁

Okay... so coming back to topic, how do we specify which file to be used by django, good thing django comes with a variable which stores this info for which settings file to choose

export DJANGO_SETTINGS_MODULE=mysite.settings.local

and we can specify the setting file to choose while running a certain command as well like

python manage.py makemigrations --settings=mysite.settings.local

since we will be using manage.py tool on local mostly we specify the local settings file in manage.py file

import os
import sys

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings.local")

....

likewise we can specify the production settings by default in mysite/wsgi.py file as local runserver is not using it and it will only be used in production in most cases

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings.staging")

this is the basics of how you can set up a project to work seamlessly in local as well as the production environment.



About author

Shahraiz Ali

I'm a passionate software developer and researcher from Pakistan. I like to write about Python, Django and Web Development in general.


Load more
Scroll to Top