Welcome to Part 3 of the series on how we set up and dockerise every new Django project at Webinative.
In part 1, we created a new Django project with a core app and custom User model.
In part 2, we added some useful third-party Django apps and python packages to our project.
This article will focus on abstracting some key configurations into environment variables.
In a typical organisation, we run a Django project in one or more of the following environments,
Some of the project's configurations/settings change depending on the runtime environment. For example, consider the
Moreover, it is good practice to have a unique
SECRET_KEY for every environment.
The old-school approach is to have multiple
settings.py files — one for each environment like
settings_beta.py, etc. But saving your secrets in Git or any VCS is not recommended (see 12-factor principles). A better approach is to use environment variables.
.env file within your project root (same level as
Note: Files and folders starting with a dot in their name remain hidden in Linux and Mac.
We'll identify the config that could change with environments and move them into this file.
# contents of .env DJANGO_ALLOWED_CIDR_NETS=192.168.0.0/24 DJANGO_ALLOWED_HOSTS=localhost DJANGO_DEBUG=True DJANGO_INTERNAL_IPS=127.0.0.1 DJANGO_TIME_ZONE=UTC DJANGO_SECRET_KEY="django-insecure-q-*[email protected]=l+f=96%!9%vpm8h)jdw)gpw7)i41c94k"
Note: The prefix
DJANGO_acts as a namespace for these ENV vars.
Next, we'll update
settings.py to read these values from the environment.
import os SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') DEBUG = os.getenv('DJANGO_DEBUG') ALLOWED_HOSTS =  ALLOWED_HOSTS_ENV = os.getenv('DJANGO_ALLOWED_HOSTS') if ALLOWED_HOSTS_ENV: ALLOWED_HOSTS = ALLOWED_HOSTS_ENV.split(',') if DEBUG: ALLOWED_CIDR_NETS_ENV = os.getenv('DJANGO_ALLOWED_CIDR_NETS') if ALLOWED_CIDR_NETS_ENV: ALLOWED_CIDR_NETS = ALLOWED_CIDR_NETS_ENV.split(',') INTERNAL_IPS_ENV = os.getenv('DJANGO_INTERNAL_IPS') if INTERNAL_IPS_ENV: INTERNAL_IPS = INTERNAL_IPS_ENV.split(',') # ... TIME_ZONE = os.getenv('DJANGO_TIME_ZONE', 'UTC')
Tip: Adding the
.env file to our project's
.gitignore ensures Git doesn't track this file.
Now, try running the development server.
# within your project folder workon dockerise_django ./manage.py runserver 0:8000
You should see an error as shown below,
Why? We have abstracted some settings into a
.env file but not loaded them into our virtual environment.
Let us load the contents of the
.env file into our virtual environment and then run the development server.
# load contents of .env file set -o allexport; source .env; set +o allexport # runserver ./manage.py runserver 0:8000
The development server now runs without errors.
Tip: You can use the
postactivate hook to load the
.env file every time the virtual environment is activated.
Add the following lines to the
set -o allexport; source $HOME/Dev/dockerise-django/.env; set +o allexport
You can test the
postactivate hook using the following commands,
deactivate workon dockerise_django echo $DJANGO_ALLOWED_HOSTS # should print localhost ./manage.py runserver 0:8000 # should run the dev server without any errors
As you move forward and add more apps to your project, remember to identify and abstract environment-specific configuration into the
As usual, you can clone this GitHub repository and checkout the
part_03/env_vars branch to see the completed code.
In the next part, we will start containerising the application.
Like this article? Have a comment to share or a question to raise? Join our Discord server.