|
| 1 | +# Django and PostgreSQL setup in Docker |
| 2 | + |
| 3 | +Here is how to dockerize a Django app along side a PostgreSQL database container. |
| 4 | + |
| 5 | +This guide shows how to integrate the following tools: |
| 6 | + |
| 7 | +- Docker containers |
| 8 | +- uv package manager |
| 9 | +- Django app |
| 10 | +- PostgreSQL database |
| 11 | + |
| 12 | + |
| 13 | +## Setup project |
| 14 | + |
| 15 | +Project folder structure: |
| 16 | + |
| 17 | +```bash |
| 18 | +test-django-docker |
| 19 | +├── .venv |
| 20 | +├── my_django_app |
| 21 | +│ ├── my_django_app |
| 22 | +│ ├── core |
| 23 | +│ └── manage.py |
| 24 | +├── pyproject.toml |
| 25 | +├── readme.md |
| 26 | +├── requirements.txt |
| 27 | +└── uv.lock |
| 28 | +``` |
| 29 | + |
| 30 | +To set this up we create a root folder: |
| 31 | + |
| 32 | +```bash |
| 33 | +mkdir test-django-docker |
| 34 | +cd test-django-docker |
| 35 | +``` |
| 36 | + |
| 37 | +Since we are using `uv` to manage packages and environments we initiate it: |
| 38 | + |
| 39 | +```bash |
| 40 | +uv init . |
| 41 | +``` |
| 42 | + |
| 43 | +Now lets create the Django project `my_django_app` and create the app `core`. |
| 44 | + |
| 45 | +```bash |
| 46 | +uv run django-admin startproject my_django_app |
| 47 | +cd my_django_app |
| 48 | +uv run python manage.py startapp core |
| 49 | +``` |
| 50 | + |
| 51 | +On the root folder create a `requirements.txt` file: |
| 52 | + |
| 53 | +```bash |
| 54 | +cd .. |
| 55 | +uv pip freeze > requirements.txt |
| 56 | +``` |
| 57 | + |
| 58 | + |
| 59 | +## Adding `gunicorn` |
| 60 | + |
| 61 | +Django `manage.py runserver` is only meant for development purposes and should be changed for a WSGI server for production. |
| 62 | + |
| 63 | +```bash |
| 64 | +uv add gunicorn |
| 65 | +uv add "psycopg[binary]" |
| 66 | +uv pip freeze > requirements.txt |
| 67 | +``` |
| 68 | + |
| 69 | + |
| 70 | +## Create a Dockerfile |
| 71 | + |
| 72 | +A Dockerfile is a script that tells Docker how to build your Docker image. Put it in the root directory of your Django project. Here’s a basic Dockerfile setup for Django: |
| 73 | + |
| 74 | +```dockerfile |
| 75 | +# Use the official Python runtime image |
| 76 | +FROM python:3.11.13-slim-bookworm |
| 77 | + |
| 78 | +# Create the app directory |
| 79 | +RUN mkdir /app |
| 80 | + |
| 81 | +# Set the working directory inside the container |
| 82 | +WORKDIR /app |
| 83 | + |
| 84 | +# Set several environment variables: |
| 85 | +# Prevents Python from writing pyc files to disk |
| 86 | +ENV PYTHONDONTWRITEBYTECODE=1 |
| 87 | + |
| 88 | +# Prevents Python from buffering stdout and stderr |
| 89 | +ENV PYTHONUNBUFFERED=1 |
| 90 | + |
| 91 | +# Upgrade pip |
| 92 | +RUN pip install --upgrade pip |
| 93 | + |
| 94 | +# Copy the Django project and install dependencies |
| 95 | +COPY requirements.txt /app/ |
| 96 | + |
| 97 | +# Install all dependencies |
| 98 | +RUN pip install --no-cache-dir -r requirements.txt |
| 99 | + |
| 100 | +# Copy the Django project to the container |
| 101 | +COPY . /app/ |
| 102 | + |
| 103 | +# Expose the Django port |
| 104 | +EXPOSE 8000 |
| 105 | + |
| 106 | +# Run Django development server |
| 107 | +# CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] |
| 108 | + |
| 109 | +# Start the application using Gunicorn |
| 110 | +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "my_django_app.wsgi:application"] |
| 111 | +``` |
| 112 | + |
| 113 | +Build the Docker container: |
| 114 | + |
| 115 | +```bash |
| 116 | +docker build -t django-docker . |
| 117 | +``` |
| 118 | + |
| 119 | +To see your image, you can run: |
| 120 | + |
| 121 | +```bash |
| 122 | +docker image list |
| 123 | +``` |
| 124 | + |
| 125 | + |
| 126 | +## Configure the Docker Compose file |
| 127 | + |
| 128 | +A `docker-compose.yml` file allows you to manage multi-container applications. Here, we'll define both a Django container and a PostgreSQL database container. |
| 129 | + |
| 130 | +```yaml |
| 131 | +services: |
| 132 | + web: |
| 133 | + build: . |
| 134 | + container_name: django_app |
| 135 | + ports: |
| 136 | + - "8000:8000" |
| 137 | + volumes: |
| 138 | + - ./my_django_app:/app |
| 139 | + depends_on: |
| 140 | + db: |
| 141 | + condition: service_healthy |
| 142 | + restart: true |
| 143 | + env_file: |
| 144 | + - .env |
| 145 | + db: |
| 146 | + image: postgres:17 |
| 147 | + container_name: postgres_db |
| 148 | + environment: |
| 149 | + POSTGRES_DB: ${POSTGRES_DB} |
| 150 | + POSTGRES_USER: ${POSTGRES_USER} |
| 151 | + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} |
| 152 | + healthcheck: |
| 153 | + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] |
| 154 | + interval: 10s |
| 155 | + retries: 5 |
| 156 | + start_period: 30s |
| 157 | + timeout: 10s |
| 158 | + ports: |
| 159 | + - "5432:5432" |
| 160 | + volumes: |
| 161 | + - postgres_db:/var/lib/postgresql/data |
| 162 | + env_file: |
| 163 | + - .env |
| 164 | +volumes: |
| 165 | + postgres_db: |
| 166 | +``` |
| 167 | +
|
| 168 | +The compose file makes use of an environment file called `.env`, which will make it easy to keep the settings separate from the application code. |
| 169 | + |
| 170 | +``` |
| 171 | +POSTGRES_DB=postgres_db |
| 172 | +POSTGRES_USER=dbuser |
| 173 | +POSTGRES_PASSWORD=dbpassword |
| 174 | +POSTGRES_HOST=db |
| 175 | +POSTGRES_PORT=5432 |
| 176 | +``` |
| 177 | +
|
| 178 | +
|
| 179 | +## Update Django settings and configuration files |
| 180 | +
|
| 181 | +Let's update the `setting.py` file by: |
| 182 | +
|
| 183 | +- Adding the `core` app. |
| 184 | +
|
| 185 | +- Change some variables to enable them to be set using environment variables when the container is started. This allows you to change these settings depending on the environment you are working in. |
| 186 | +
|
| 187 | +- Configure the database settings to use PostgreSQL. |
| 188 | +
|
| 189 | +```python |
| 190 | +import os |
| 191 | +
|
| 192 | +# ... |
| 193 | +
|
| 194 | +SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY") |
| 195 | + |
| 196 | +DEBUG = bool(os.environ.get("DEBUG", default=0)) |
| 197 | + |
| 198 | +ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS","127.0.0.1").split(",") |
| 199 | +
|
| 200 | +# ... |
| 201 | +
|
| 202 | +INSTALLED_APPS = [ |
| 203 | + # ... |
| 204 | + 'core', |
| 205 | +] |
| 206 | +
|
| 207 | +# ... |
| 208 | +
|
| 209 | +DATABASES = { |
| 210 | + 'default': { |
| 211 | + 'ENGINE': 'django.db.backends.postgresql', |
| 212 | + 'NAME': os.environ['POSTGRES_DB'], |
| 213 | + 'USER': os.environ['POSTGRES_USER'], |
| 214 | + 'PASSWORD': os.environ['POSTGRES_PASSWORD'], |
| 215 | + 'HOST': os.environ['POSTGRES_HOST'], |
| 216 | + 'PORT': os.environ['POSTGRES_PORT'], |
| 217 | + } |
| 218 | + } |
| 219 | +``` |
| 220 | + |
| 221 | + |
| 222 | + |
| 223 | + |
| 224 | + |
| 225 | +## References |
| 226 | + |
| 227 | +- [Docker - Django and PostgreSQL setup (with uv) from scratch!](https://www.youtube.com/watch?v=37aNpE-9dD4) |
| 228 | + |
| 229 | +- [How to Dockerize a Django App: Step-by-Step Guide for Beginners](https://www.docker.com/blog/how-to-dockerize-django-app/) |
| 230 | + |
| 231 | +- [Dockerizing Django with Postgres, Gunicorn, and Nginx](https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/) |
0 commit comments