Settings for Multiple Environments in Django

Multiple Settings File

So far, a single file has served us well. Now we are moving to the production environment, as a result, some of the settings in file needs to be changed. Most notably, we will change DEBUG to False and ALLOWED_HOSTS to the production server IP or domain.

To efficiently run our Django project in different environments, we will split our single into multiple files, each one representing settings for a particular environment.

Let’s start by renaming to and creating a directory named settings in the Django configurations directory (djangobin/django_project/django_project). Inside the settings directory create following four files:


The file tells Python that the settings directory is a package. The contains the settings common to development and production environment. The and contains the settings specific to the development and production respectively.

At this point, Django configurations directory should look like this:

The complete code of is as follows (changes are highlighted):


Here are few things to notice:

* For security reasons, you must never hardcode sensitive configurations like SECRET_KEY, database credentials, or API keys in your code. Furthermore, these configurations are also subject to change across deploys. If you put these configurations in the code then you would have to constantly update the code everytime you move to a new environment.

In our case, we have stored all our sensitive configurations in a JSON file named djangobin-secrets.json, which resides in project root directory (djangobin/django_project). The contents of djangobin-secrets.json looks like this:


This file contains the SECRET_KEY, database credentials and email credentials. If you are using a version control system (which you should) add this file to .gitignore.

To generate the secret key we the get_random_string() function of django.utils.crypto module:

In production, we will use PostgreSQL as our database and SendGrid to send emails.

If you already know how to install and configure PostgreSQL, go ahead and populate the database credentials, otherwise, wait until the next lesson where we will look at how to install and configure PostgreSQL.

To obtain the email credentials sign up for a free account on SendGrid. As of this writing, SendGrid free plan allows you to send 100 email daily.

Back to file.

In lines 16-17, we read the contents of djangobin-secrets.json file and store it in the secrets variable as a dictionary.

If you try to access a configuration which doesn’t exist in the secrets directory, you will get a KeyError exception. Sadly, this is not very helpful. To make debugging easier we have defined get_secret_setting() function. This method returns the value of the setting it is called with or an ImproperlyConfigured exception if the setting is not found in the secrets directory.

* Our settings file is now one level deep inside the Django configurations directory. In other words, the BASE_DIR setting no longer points to project root directory (djangobin/django_project/) instead it points to the Django configurations directory (djangobin/django_project/django_project). This effectively breaks the path to templates, static files and media files. To account for this, in line 27, we have we added an additional call to os.path.dirname(). This will make sure that the BASE_DIR setting points to the correct base directory.

* In line 23, we have added 'django.middleware.common.BrokenLinkEmailsMiddleware' to the MIDDLEWARE list. This will email the MANAGERS whenever an HTTP 404 error occurs.

The code for is as follows:


Nothing fancy here, the just contains development specific settings. To import the common settings from we use from .base import * statement (line 1). Note that we have deliberately hardcoded some of the sensitive configurations because it makes the development process easy. However, this is not the case with file.


The is almost similar to but it defines settings specific to the production environment.

Here are few things to notice:

1. Unlike, in we are loading our sensitive configurations via get_secret_setting() function defined in the file.

2. In line 10, we set ALLOWED_HOSTS to [*]. ALLOWED_HOSTS setting is a security feature which is used to validate whether the request is coming from allowed domains or not. It specifies a list of a string representing host/domain names this Django project can serve. By default, it is set to an empty list. Once you move to production you required to set it otherwise you will get 500 Internal Server Error.

If you own and want to allow requests from or then you would need to set ALLOWED_HOSTS to:

If you want to allow requests from and all its subdomains then use the period as a subdomain wildcard. For example:

To allow Django to accept requests from any domain set ALLOWED_HOSTS to “*”.

However, in a real deploy, you should limit this setting only to the host/domain you want to allow.

3. In lines 15-19, we define configurations to connect to PostgreSQL database.

4. In lines 25-28, we define settings required to send emails via SendGrid.

Running Project

We have refactored our code quite a lot. Now let’s take a look at how we can interact with our Django project with this new setup.

In the terminal execute ./ file and you will get the error as follows:

You will get the same error (just different wording) if you try to run the runserver or shell command.

The problem is that the Django doesn’t know where our settings file is located. We can specify the location of settings file from the command line using the --setting option.

Note that you will need to specify --settings option everytime you execute the script. For example:

Specifying the --settings option everytime you execute ./ file can quickly become tedious. Alternatively, you can set the DJANGO_SETTINGS_MODULE environment variable to the desired settings file as follows:

You can now execute the ./ as usual without specifying the path to the settings file.

The DJANGO_SETTINGS_MODULE variable will remain in existence until the shell session is active. Unfortunately, If you start a new shell you will have to set DJANGO_SETTINGS_MODULE again.

A much better approach would be to modify the virtualenv’s activate script and set DJANGO_SETTINGS_MODULE environment variable when activating the virtualenv and unset it when deactivating the virtualenv.

Open activate script and modify it as follows:


Start a new shell, activate the virtual environment and check the existence of DJANGO_SETTINGS_MODULE environment variable using the echo command:

As expected, DJANGO_SETTINGS_MODULE environment variable is available.

Now you can run ./ file without setting any environment variable or specifying the --settings option

Start the Django development server to make sure everything is working as expected.

The output should look like this:

The DJANGO_SETTINGS_MODULE variable will be automatically removed upon deactivating the virtual environment.

Creating Requirements file

A requirements file is a simple text file containing the project dependencies. We use the requirements file to install the project dependencies.

To create the requirements file execute the following command:

Our DjangoBin project is now complete. In the next lesson, we will learn how to deploy it to the DigitalOcean server.

3 thoughts on “Settings for Multiple Environments in Django

  1. Thank you very much for very nice nice tutorial on Django. Your tutorials have helped me a lot to understand Django from Scratch.

    In this tutorial, “How to set up Multiple environments for Django” for securing credentials are very clearly explained.
    But, Sir, How to secure the API key’s used in JavaScript.
    For example, the key used for accessing google maps will be sent to client. “<script src=””>”.

    Please guide me, how to secure these type of Keys.

    Thanks and regards for giving us knowledge for FREE

    Bala Subramanyam

  2. Thanks for your tutorial, it helped me very much!

    I found an easier way to set the DJANGO_SETTINGS_MODULE variable, I’d like to share it with you. Basically, the way I usually run things, is that I develop locally and deploy on docker containers. In Docker containers it is easy to set environment variables at container boot time, so the variable is easy to set. But in development there is no such thing. So an easy work around is to go in and edit the following lines of code:


    Replace them by the following:


    This way, if the environment variable is not set, it points to the development one, but if it is, it will take the one that is already defined (setdefault only sets the value of the environment variable if it is not already defined). This is actually the Django built-in solution, we just need to point the default settings file to the one we just created.

    This is much more “Djangonic” (i.e. pythonic within Django) than a bash or .env file hack!

Leave a Comment

%d bloggers like this: