Django - Separate local/development/production environments

By khoanc, at: March 21, 2023, 2:13 p.m.

Estimated Reading Time: 13 min read

Django - Separate local/development/production environments
Django - Separate local/development/production environments

1. Introduction of Django settings


Django - a popular Python web framework - provides a robust set of features to build web applications. When working on a Django project, developers have to manage various settings, such as database settings, email settings, security settings, and more. These settings can be different for different environments, such as local, development, and production.

In this article, we'll explore why it's important to separate local/development/production environments in Django and how to do it.

 

2. The problems with mixing different environments in Django settings


Mixing different environments in Django settings can lead to various problems, such as


2.1 Security vulnerabilities

Exposing sensitive information, such as database credentials and secret keys, in the settings files can pose a security threat. 

For example:

# settings.py
SECRET_KEY = 'my-secret-key'
DEBUG = True
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}


In the example above, the SECRET_KEY and database credentials are exposed in the settings.py file, which could be compromised if the file is accessed by an unauthorized user.


2.2 Inconsistent behavior

Using the same settings for different environments can result in inconsistent behavior, such as database collisions and file conflicts. 

For example:

# settings.py
STATIC_ROOT = '/var/www/static/'

# development settings
STATIC_ROOT = 'static/'

# production settings
STATIC_ROOT = '/home/user/static/'


In the example above, the STATIC_ROOT setting is set to different values for different environments, which can lead to file conflicts and inconsistent behavior when deploying the application.


2.3 Difficulty in debugging

Debugging issues in a mixed environment can be challenging and time-consuming.

For example:

# settings.py
DEBUG = True

# production settings
DEBUG = False


In the example above, the DEBUG setting is set to True in the settings.py file but set to False in the production settings. This can make it difficult to debug issues that only occur in the production environment.

By separating the settings for different environments, we can avoid these problems and achieve better control and flexibility over our projects.


3. How to solve the problems, useful packages, pros and cons


To solve the problems associated with mixing different environments in Django settings, we can use various techniques and packages. Here are some options:


3.1 Environment variables

One of the most popular approaches is to use environment variables to store configuration values for different environments. This way, we can keep sensitive information like database credentials and API keys out of the codebase, and configure the app using variables provided by the environment.

For example:

# settings.py
SECRET_KEY = os.environ.get('SECRET_KEY')
DEBUG = os.environ.get('DEBUG')
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DATABASE_NAME'),
        'USER': os.environ.get('DATABASE_USER'),
        'PASSWORD': os.environ.get('DATABASE_PASSWORD'),
        'HOST': os.environ.get('DATABASE_HOST'),
        'PORT': os.environ.get('DATABASE_PORT'),
    }
}


In this example, we are using the os.environ.get method to retrieve values from environment variables for sensitive information like SECRET_KEY and database credentials.

Pros

  • Enhances security by keeping sensitive data out of the codebase
     
  • Provides greater flexibility for managing configurations across different environments
     

Cons

  • Requires manual configuration and setup of environment variables for each environment
     
  • Can be hard to keep track of different variables and their values, leading to errors and inconsistencies


3.2 Configuration files

Another option is to use separate configuration files for each environment. This way, we can keep the configuration values for each environment in a dedicated file and avoid mixing them up.

For example:

# settings.py
SECRET_KEY = 'my-secret-key'
DEBUG = True
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}


The development.py file

# development.py
from .settings import *
DEBUG = True
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase_dev',
        'USER': 'mydatabaseuser_dev',
        'PASSWORD': 'mypassword_dev',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}


The production.py file

# production.py
from .settings import *
DEBUG = False
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase_prod',
        'USER': 'mydatabaseuser_prod',
        'PASSWORD': 'mypassword_prod',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}


In this example, we have created separate files for each environment, and imported the settings.py file to inherit the base settings and override the relevant configuration values.

Pros

  • Provides clear separation of configuration values for each environment
     
  • Can be easily version-controlled and managed using a source control system
     

Cons

  • Can be cumbersome to maintain and manage for large projects with multiple environments
     
  • Requires additional setup and configuration for each environment, leading to duplication of code and potential for errors


3.3 Third-party packages

Django also provides several third-party packages to manage environment-specific configurations, such as django-environ, django-configurations, and django-dotenv. These packages provide a structured and consistent way to manage configurations across different environments, and can simplify the process of managing sensitive information.

Pros

  • Provides a structured and consistent way to manage configurations
     
  • Simplifies the process of managing sensitive information
     

Cons

  • Requires additional dependencies and setup
     

Some useful packages

You can find more useful packages here


4. The best practices for setup Django settings with different environments


Here are some best practices for setting up Django settings with different environments

  • Keep it simple: It's important to keep the configuration process simple and easy to manage. Avoid overcomplicating the process by adding unnecessary layers of abstraction or complexity.
     
  • Use version control: Use a version control system to track changes to configuration files across different environments. This ensures that changes are tracked, and any issues can be quickly identified and fixed.
     
  • Use environment variables: Use environment variables to store sensitive configuration values like database credentials and API keys. This ensures that sensitive information is kept separate from the codebase and is not accidentally shared or leaked.
     
DATABASE_URL = os.environ.get('DATABASE_URL')
SECRET_KEY = os.environ.get('SECRET_KEY')
  • Use a consistent naming convention: Use a consistent naming convention for environment variables, configuration files, and settings to ensure consistency and avoid confusion. For example, use DATABASE_URL as an environment variable for the database URL.
  • Use default settings: Use default settings to ensure that the app runs smoothly in the absence of specific environment configurations. This ensures that the app can be run easily and quickly without specific configurations.
# settings/base.py
DEBUG = False
ALLOWED_HOSTS = []


# settings/local.py
DEBUG = True
ALLOWED_HOSTS = ['localhost']

 

  • Use a package manager: Use a package manager like pip or conda to manage dependencies across different environments. This ensures that dependencies are consistent and easily installed across different environments.
# requirements.txt
Django==3.2
psycopg2-binary==2.8.6

# environment.yml
name: myenv
dependencies:
  - python=3.8
  - django=3.2
  - psycopg2=2.8.6

 

  • Test configurations: Test configurations across different environments to ensure that the app runs smoothly in each environment. This ensures that any issues are identified and fixed before they cause any problems in production.
# settings/tests.py
from .base import *

DEBUG = False
ALLOWED_HOSTS = ['test.example.com']


By following these best practices, you can ensure that your Django app is configured consistently across different environments, and is easy to manage and maintain over time.

 

5. What solutions work best with different stacks: Docker, Server Manual, Kubernetes...


Setting up Django settings with different environments can be done in several ways, depending on your stack and infrastructure. Here are some popular options:


5.1 Server manual setup

The simplest way to set up different environments for your Django app is to do it manually on each server. This involves copying the settings file to each server and modifying it as required.

For example:

$ cp settings/local.py.example settings/local.py
$ nano settings/local.py


Pros

  • Simple and straightforward.
     

Cons
 

  • Prone to human error.
     
  • Time-consuming and difficult to maintain.


5.2 Docker

Docker is a popular containerization platform that allows you to package an app and all its dependencies into a single container. Docker can be used to create separate containers for each environment, with separate configurations for each.

For example:

# Dockerfile
FROM python:3.9
ENV PYTHONUNBUFFERED=1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]


Pros
 

  • Isolates each environment in a separate container.
     
  • Easy to manage and deploy.
     

Cons

  • Requires knowledge of Docker and containerization concepts.
     
  • Requires extra effort to set up initially.
     


5.3 Kubernetes

Kubernetes is a popular container orchestration platform that allows you to manage and deploy Docker containers at scale. Kubernetes can be used to create separate pods for each environment, with separate configurations for each.

For example:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-django-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-django-app
  template:
    metadata:
      labels:
        app: my-django-app
    spec:
      containers:
      - name: my-django-app
        image: my-django-app:latest
        ports:
        - containerPort: 8000
        env:
        - name: DJANGO_SETTINGS_MODULE
          value: my_django_app.settings.production


Pros
 

  • Easy to manage and deploy.
     
  • Isolates each environment in a separate pod.
     

Cons
 

  • Requires knowledge of Kubernetes and container orchestration concepts.
     
  • Requires extra effort to set up initially.
     

It's important to note that the best solution for your app will depend on your specific requirements and infrastructure. However, Docker and Kubernetes are becoming increasingly popular for managing different environments in Django apps.

In addition, the community and blog posts recommend using tools like django-environ, python-decouple, and django-configurations to help manage settings across different environments. These tools provide a simple and consistent way to manage settings, and can be easily integrated into your app.

 

6. Conclusion

Separating local/development/production environments in Django is essential for building and deploying web applications that work consistently and securely. By using techniques such as Python Decouple, Django-environ, or separate settings files, developers can avoid the problems of mixing environments in the settings and achieve better control and flexibility over their projects. It's also important to follow the best practices for setting up Django settings and choose the appropriate solution for the deployment stack.
 


Related

Subscribe

Subscribe to our newsletter and never miss out lastest news.