Dockerizing a Django Application with Postgres as database | Compose
Published: 2023-06-20 17:37:21

---
title: Dockerizing a Django Application with Postgres as database | Compose
published: true
date: 2023-02-06 15:14:39 UTC
tags: 
canonical_url: https://carlosmv.hashnode.dev/dockerizing-a-django-application-with-postgres-as-database-compose
---

For this article, we are going to build two container images, one for a Django service and another for the Postgres database, and run them together using Compose.

### Requirements

- Docker Compose or Docker Desktop installed

We are not going to build the Django application from scratch. We will use a blank project from [this repository](https://github.com/carlosm27/django-postgres-demo). Or, you can create a new Django project if you want.

We can clone the app using GitHub CLI:

```
gh repo clone carlosm27/django-postgres-demo

```

Or using Git CLI:

```
git clone https://github.com/carlosm27/django-postgres-demo

```

### Project structure.

```
django_auth/
django_postgres/
manage.py
Dockerfile
docker-compose.yml
requirements.txt

```

### What is Compose?

According to the [Docker documentation](https://docs.docker.com/get-started/08_using_compose/):

> [Docker Compose](https://docs.docker.com/compose/) is a tool that was developed to help define and share multi-container applications. With Compose, we can create a YAML file to define the services and with a single command, can spin everything up or tear it all down.

With Compose we can define an application stack in a file, keep it at the root of our project and enable someone else to contribute to our project.

### Adding Postgres

We need to add a Postgres adapter to our Django application.

```
pip install psycopg2
pip freeze > requirements.txt

```

Inside `django_postgres/django_auth/settings.py` file we go to the database section, and it will look like this:

```
DATABASES = {
    'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

```

Our Django project is configured to use sqlite3 as a database. We change the configuration to use Postgres.

```
DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': '<YOUR PASSWORD>',
        'HOST': 'localhost',
        'PORT': 5432,
    }
}

```

### Dockerfile

```
FROM python:3.11

RUN mkdir /code
WORKDIR /code
RUN pip install --upgrade pip
COPY requirements.txt /code/

RUN pip install -r requirements.txt
COPY . /code/

EXPOSE 8000

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

```

Instead of writing our own Dockerfile, we will copy the Django sample from the [Docker samples repository.](https://github.com/dockersamples/link-shortener-django/blob/master/src/urlshortener/Dockerfile)

### Docker Compose file

As the [documentation](https://docs.docker.com/compose/compose-file/) says, the Docker Compose file is a YAML file to define services, networks, and volumes for a Docker application. Allows us to define a platform-agnostic container-based application.

The computing components of an application are defined as Services. A Service is an abstract concept implemented on platforms by running the same container image (and configuration) one or more times. Services store and share persistent data in Volumes.

We are going to use Volumes further in this tutorial to store our Postgres data.

For more information about the Docker Compose file, visit its [documentation](https://docs.docker.com/compose/compose-file/).

docker-compose.yml

```
version: "2.13.0"
services:
  web:
    build: .

    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code 
    ports:
      - "8000:8000"   
    depends_on:
      - db
  db:
    image: postgres:13
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - "POSTGRES_HOST_AUTH_METHOD=trust"

volumes:
  postgres_data:

```

Here we declare two services, a `web` service and a `db`service. This means we will have a container for the Django application and another for the Postgres database.

Also, we have to write that our `web` service depends on the `db` service to run. We add the line `depends_on` to specify this relationship.

While containers can create, update, and delete files, those changes are lost when we stop running the container because all changes are isolated to that container. With volumes, we can change all of this.

As the Docker documentation says:

> [Volumes](https://docs.docker.com/storage/volumes/) provide the ability to connect specific filesystem paths of the container back to the host machine. If a directory in the container is mounted, changes in that directory are also seen on the host machine. If we mount that same directory across container restarts, wed see the same files.

As Will Vicent explains in [this article](https://learndjango.com/tutorials/django-docker-and-postgresql-tutorial), we need to create a `volumes` called `postgres_data` in our `docker-compose.yml` and then bind it to a dedicated directory within the container at the location `/var/lib/postgresql/data/` .

Before we build the images, we have to modify the `settings.py` file of our Django service. We need to replace the host for `db` instead `localhost`.

settings.py

```
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': "<YOUR DATABASE NAME>",
        'USER': "<YOUR USER>",
        'PASSWORD': "<YOUR PASSWORD>",
        'HOST': db,
        'PORT': 5432,
    }
}

```

Now, where `docker-compose.yml` file is located, we execute this command to start the containers:

```
docker-compose up -d --build

```

When the containers start running, we go to `http://localhost:8000/` , if we see the Django welcome page, it means it worked.

After we create a table, we run migrations. When a Django application is running within a container, we execute this command to run migrations:

```
 docker-compose exec web python manage.py migrate

```

The difference is that we need to specify which service we want it to pass the command to. In this case, to `web` service.

### Conclusion

We only build and run two services, but it is possible to add many more with Compose.

It was the first time I used Compose. It allows us to build images and run containers for more robust applications that need many services to run together, with databases, cache, message brokers, event streamers, etc.

Thank you for taking the time to read this article.

If you have any recommendations about other packages, architectures, how to improve my code, my English, or anything; please leave a comment or contact me through [**Twitter**](https://twitter.com/Carlos_marcv), or [**LinkedIn**](https://www.linkedin.com/in/carlos-marcano-a2135a134/).

### References

- [Containerize an application](https://docs.docker.com/get-started/02_our_app/)

- [Docker Compose](https://docs.docker.com/get-started/08_using_compose/)

- [Docker Compose file](https://docs.docker.com/compose/compose-file/)

- [Persist the DB](https://docs.docker.com/get-started/05_persisting_data/)

- [Use bind mounts](https://docs.docker.com/get-started/06_bind_mounts/)

- [Django samples](https://docs.docker.com/samples/django/)

- [Django, Docker and Postgres Tutorial](https://learndjango.com/tutorials/django-docker-and-postgresql-tutorial)