Feel free to contact.
Shahraiz Ali
28 Sep 2019
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 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..
- we want our settings file to be short and easy to work with whereas this method is doing the opposite.
- 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
- base.py (containing common settings among all environments)
- local.py (settings specific to local environment)
- production.py
- staging.py
- __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.localand we can specify the setting file to choose while running a certain command as well like
python manage.py makemigrations --settings=mysite.settings.localsince 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.