NOTE: This article was initially posted on my Substack, at https://andresalvareziglesias.substack.com/
Hi everyone!
Now, we can serve both dynamic and static files, and we have a single entry point for our app. The next step is to add a DB engine to our stack.
Let 's get started!
Articles in this series
- Chapter 1: Let the journey start
- Chapter 2: Create a containerized Django app with Gunicorn and Docker
- Chapter 3: Serve Django static files with NGINX
- Chapter 4: Adding a database to our stack
- Chapter 5: Applications and sites
- Chapter 6: Using the Django ORM
- Chapter 7: Users login, logout and register
Why PostgreSQL/TimescaleDB?
I choose TimescaleDB (a PostgreSQL extension for time series) for the following reasons:
- I'm already familiar with PostgreSQL, an almost indestructible DB engine, tested in production environments for years.
- I want to learn how to use the TimescaleDB extension
- Because... why not?
Add TimescaleDB container
Create a new directory for the new container:
cd tic-magical-line
mkdir db
Inside the db folder, create the same three files than in other containers:
cd tic-magical-line/db
touch Dockerfile
touch environment.env
touch requirements.txt
Write environment.env required variables (write your own user/password, this is used only for demo purposes):
POSTGRES_USER=tic
POSTGRES_PASSWORD=drag0n
PGUSER=tic
Write the following content in Dockerfile:
FROM timescale/timescaledb-ha:pg16
Add the container to docker-compose file
Modify the docker-compose file adding dependencies between containers and the new TimescaleDB container. We are also adding a health-check to the database container:
version: "3.8"
services:
app:
build:
context: ./
dockerfile: ./app/Dockerfile
container_name: app
hostname: app
restart: always
volumes:
- ./src/:/usr/src/app/
depends_on:
db:
condition: service_healthy
env_file:
- ./app/environment.env
networks:
django_net:
ipv4_address: 10.20.30.1
server:
build:
context: ./
dockerfile: ./server/Dockerfile
container_name: server
hostname: server
restart: always
depends_on:
db:
condition: service_healthy
env_file:
- ./server/environment.env
ports:
- 8080:8080
networks:
django_net:
ipv4_address: 10.20.30.2
db:
build:
context: ./
dockerfile: ./db/Dockerfile
container_name: db
hostname: db
restart: always
env_file:
- ./db/environment.env
volumes:
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: [ "CMD-SHELL", "pg_isready", "-d", "ticmagicalline" ]
interval: 30s
timeout: 10s
retries: 3
networks:
django_net:
ipv4_address: 10.20.30.3
networks:
django_net:
ipam:
config:
- subnet: 10.20.30.0/24
gateway: 10.20.30.254
As you can see, one of the lines of the DB container specifies an SQL file to execute at container start. This is very useful to initialize the DB. We need to create the database that the Django app will use.
Create the SQL file:
cd tic-magical-line/db
touch init.sql
Write the following content:
CREATE DATABASE ticmagicalline;
Configure the database in Django
Edit settings.py inside Django app source code folder, and set the following variables to configure the database backend:
DATABASES = {
'default': {
"ENGINE": "django.db.backends.postgresql",
"NAME": "ticmagicalline",
"USER": "tic",
"PASSWORD": "drag0n",
"HOST": "10.20.30.3",
"PORT": "5432",
}
}
NOTE: Write your chosen password in this code block
After configuring the backend and creating the database, we need to populate it with the default tables and data. This is done with the manage.py command, inside the container:
- Get the Django app container ID: docker ps | grep tic-magical-line_app
- Enter in the container shell: docker exec -it 5e1d486aff24 /bin/bash
- Go to app folder: cd /
- Execute migration: python manage.py migrate
- Exit from the shell: exit
Also, we need to create an admin user:
- Get the Django app container ID: docker ps | grep tic-magical-line_app
- Enter in the container shell: docker exec -it 5e1d486aff24 /bin/bash
- Go to app folder: cd /
- Create user: python manage.py createsuperuser
- Exit from the shell: exit
We can automate all these changes using the main app Dockerfile. Edit it with this content:
FROM python:3.12.2-bookworm
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN pip install --upgrade pip
COPY ./app/requirements.txt .
RUN pip install -r requirements.txt
COPY ./app/entrypoint.sh .
RUN chmod +x entrypoint.sh
COPY ./app/src/ticmagicalline .
ENTRYPOINT [ "/entrypoint.sh" ]
Then, create the new entrypoint.sh file: with:
#!/bin/sh
echo "Executing Django DB migration..."
python manage.py migrate
echo "Creating Django administrator..."
python manage.py createsuperuserwithpassword \
--username $DJANGO_ADMIN_USERNAME \
--password $DJANGO_ADMIN_PASSWORD \
--email $DJANGO_ADMIN_EMAIL \
--preserve
echo "Initial tasks finalized!"
gunicorn ticmagicalline.wsgi:application --bind 0.0.0.0:8081
Add the new variables to environment.env file:
DJANGO_ADMIN_USERNAME=tic
DJANGO_ADMIN_EMAIL=tic@fake.com
DJANGO_ADMIN_PASSWORD=drag0n
And add the new dependency to requirements.txt:
Django
gunicorn
psycopg2-binary
django-createsuperuserwithpassword
Don't forget to edit the Django app settings to enable the new createsuperuserwithpassword extension adding the following line to settings.py:
INSTALLED_APPS += ("django_createsuperuserwithpassword", )
Rebuild the images and execute again
After all these changes, we need to rebuild the new images with:
docker-compose stop
docker-compose build
After the data population, start the cluster again with:
docker-compose up
Now, we can test the database integration login into the Django admin site, with this link:
http://localhost:8080/admin/login/?next=/admin/
Use the username and password defined in the previous step. And voilá! We are now inside our Django app admin site!
About the list
Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:
- Software architecture
- Programming environments
- Linux operating system
- Etc.
If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!
About the author
I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!
Top comments (0)