1

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 Answers 3

2

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.

.my_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")

           # ...
        }
    }
Sign up to request clarification or add additional context in comments.

Comments

1

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}

Comments

0

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

3 Comments

It doesn't work in my case. It says ValueError: Port could not be cast to integer value as '$DB_PORT' when I run it without docker. I haven't tested it with Docker setup though, will let you know a bit later!
I am guessing your django app isn't containerised? django-environ does not do variable expansion when parsing .env file while docker compose does while passing environment to containers.
Env vars in the environment attribute in a docker-compose file do not interpolate from an .env file. The .env file will pass the vars to container. Listing them in the environment attribute will essentially take precedence over anything declared in the .env file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.