django-environ and Postgres environment for docker

513 views Asked by At

I am using django-environ package for my Django project. I provided the DB url in the .env file, which looks like this: DATABASE_URL=psql://dbuser:dbpassword@dbhost:dbport/dbname

My DB settings in settings.py:

DATABASES = {
    "default": env.db(),
}

So far, I have no issues.

Then, I created a docker-compose.yml where I specified that my project uses Postgres database, i.e.:

version: '3.8'

services:
  ...
    db
      image: postgres:13
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_USER=???
      - POSTGRES_PASSWORD=???
      - POSTGRES_DB=???
      - "POSTGRES_HOST_AUTH_METHOD=trust"

Now I am confused a little.

How do I provide these POSTGRES_* env. variables there? Do I need to provide them as separate variables alongside with the DATABASE_URL in my .env file? If yes, what's the best way do accomplish this? I aim to avoid duplication in my settings.

3

There are 3 answers

0
JohnnyP On BEST ANSWER

Declare the vars in your .env file and then reference the file in the env_file attribute of Django container in docker-compose file. This is where the Django settings file can access them with os.environ.get(). Env vars in the environment attribute in a docker-compose file do not interpolate from an .env file. They would only interpolate there if the vars were exported in the shell that the compose file is run from. It helped me to view these docs when experiencing the same issue: Environment variables precedence in Docker Compose.

.env file example:

DB_NAME=my_database
DB_USER=postgres_user
DB_PASSWORD=1234567

In Django block in docker-compose file, reference your env file:

# ....
    env_file:
      - ./.my_env_file
# ...

Django settings:

import os
    
    DATABASES = {
        'default': {
           # ...

            "POSTGRES_DB": os.environ.get("DB_NAME"),
            "POSTGRES_USER": os.environ.get("DB_USER"),
            "POSTGRES_PASSWORD": os.environ.get("DB_PASSWORD")

           # ...
        }
    }
3
janezicmatej On

You can use variable expansion in your .env file. Something like

DB_NAME=dbname
DB_USER=dbuser
DB_PASSWORD=dbpassword
DATABASE_URL=psql://$DB_USER:$DB_PASSWORD@dbhost:dbport/$DB_NAME

and then something like this in your compose file

services:
  postgresdb:
    container_name: projectname_db
    image: postgres:15
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    ports:
      - "127.0.0.1:5432:5432"
...

I am not exactly familiar with django-environ but this should work

0
Seaworn On

Apparently, django-environ doesn't support variable expansion (as of v0.10.0), so the way I found is to spell out the individual options instead of using env.db()

Django settings

DATABASES = {
  "default": {
     # ...
     "NAME": env("DB_NAME"),
     "USER": env("DB_USER"),
     "PASSWORD": env("DB_PASSWORD"),
  },
}

Docker Compose

version: '3.8'

services:
  # ...
  db:
    environment:
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=${DB_NAME}