Django project - Part 1 Docker
Pedro Campos
Posted on September 30, 2024
Introduction
This is advanced content on how I structure my django for a new project. I've skipped the basic startproject and startapp, there are plenty of content on that. So, the project started with Poetry, django, .gitignore, git repo, simple home page and django-allauth.
This is for small/medium applications, like a startup/ or small business. After the business grows, you need to evolve the architecture.
The source code from this part
In this series of posts we are going to set up a django project for an efficient development environment(in my opinion). In the end, we are going to have a setup with:
- Python
- Poetry
- Django
- django-environ
- django-extentions
- django-allauth
- Just
- marimo
- ruff
- django-debug-toolbar
- pytest
- pytest-django
- gunicorn
- whitenoise
- sentry-sdk
- django-browser-reload
- htmx
- django-htmx
- tailwindcss
- alpinejs
- Docker
- Postgres
- README.md, yes it's one of the pillars.
- git, github and github actions
- Deploy the app on fly.io
- Deploy the postgres on neon.tech ... and possible more
This is a serie with 8 parts, this is the first one.
Take note that not all parts are published yet, it's an ongoing work.
- Part 1: Docker setup. Simple dockerization, even before Postgres configuration.
- Part 2: Postgres. Configure Postgres to be used in Django and the configuration in the compose.yml.
- Part 3: Continuos integration. Add Pytest, ruff, and run it on github action on PR to prevent broken code and ensure code quality.
- Part 4: HTMX, TailwindCSS and AlpineJS. Configure HTMX in the project, there is a few tricks for django. Configure nodejs on the container and the tailwind watcher in development. Configure AlpineJS, more simple than HTMX and TailwindCSS.
- Part 5: Dev Tools, Add tools like Marimo, django-extensions, django-toolbar, django-browser-reload.
- Part 6: Continuos Delivery. Configure staticfiles, in this case with whitenoise. Deploy on fly.io and neon.tech and, of course, using github action for that.
Part 1 Docker setup
I'm not going to explain what Docker is and why you should use it. I assume you know the basics.
What do we need to start?
For now, install the Docker and Just and, of course, our django project with already a simple home page, in this case using poetry.
Just
encapsulate commands for easier use. Here is an example of a justfile:
build:
docker compose build
runserver:
docker compose up --build
mng command:
docker compose run --rm web python manage.py {{command}}
sh:
docker compose run --rm web sh
and then we can run
$ just build
$ just runserver
$ just mng createsuperuser
Ok, let's create the files.
Don't worry, I'll explain each one of them.
First create all those empty files:
- docker/dev/Dockerfile - Steps to create the image
- docker/dev/start - Bash file to start the container through entrypoint on docker-compose
- compose.yml - Simple orchestration of the containers, just one for now.
- .env - Our environment variables injected into the container by compose.yml, add on .gitignore.
- .env.template - Same key as .env but with empty values for reference, this one stays on the repo.
- justfile - Wrapper for the commands.
- README.md - You know why, don't play dead.
Install django-environ
django-environ - To manage env var
$ poetry add django-environ
The Dockerfile file
# Pull official base image
FROM python:3.12.6-alpine3.19
# Set working directory in the image
WORKDIR /app
# Set env variables
# Don't write out pyc files
ENV PYTHONDONTWRITEBYTECODE 1
# No buffering stdin/stdout
ENV PYTHONUNBUFFERED 1
# update the alpine linux
RUN apk update
# install bash on image, alpine uses ash, but we have a script that uses bash
RUN apk add --no-cache bash
# Copy our poetry artifacts to the building image
COPY poetry.lock pyproject.toml /app
RUN pip3 install poetry
# No need to create a virtual env in the container
RUN poetry config virtualenvs.create false
# Install dependencies with the dev dependecies
RUN poetry install --with dev
# Copy start bash script with the instruction on how to start and serve Django.
COPY ./docker/dev/start /start
RUN sed -i 's/\r$//g' /start
RUN chmod +x /start
# Copy all project files to the image.
COPY . /app
# Not used, the app are going to be running through docker compose
CMD ["manage.py", "runserver", "0.0.0.0:8000"]
start
#!/bin/bash
set -o errexit
set -o pipefail
set -o nounset
# Apply migrations if has a new one.
echo "Running migrations..."
python manage.py migrate
# Start the server for development
echo "Starting runserver"
exec python manage.py runserver 0.0.0.0:8000
compose.yml
services:
# The service to be created on docker
web:
# how to build the image for this service
build:
# Where is the directory to work on...
context: .
# ... with what Dockerfile instructions
dockerfile: ./docker/dev/Dockerfile
image: palindrome_local
container_name: palindrome_local
volumes:
- .:/app:z
env_file:
- .env
ports:
- "8000:8000"
# The bash file to execute, the one created above and added to Dockerfile
command: /start
justfile
# List all just commands
default:
just --list
# Build the docker image
build:
docker compose build
# Run the Django app in development mode
runserver:
docker compose up --build
# Run manage.py inside the container like createsuperuser
mng command:
docker compose run --rm web python manage.py {{command}}
.env
DEBUG=True
SECRET_KEY='dev-key-(g!%yi9at$h6$*sz**^ld6+j)r305*=6i^3ho1bq=z@8c#b7ml'
ALLOWED_HOSTS=*
.env.template
Can be the same for now.
DEBUG=True
SECRET_KEY='dev-key-(g!%yi9at$h6$*sz**^ld6+j)r305*=6i^3ho1bq=z@8c#b7ml'
ALLOWED_HOSTS=*
Update settings.py
For now just these settings, the value come from .env file:
import environ
...
env = environ.Env()
SECRET_KEY = env('SECRET_KEY')
DEBUG = env.bool('DEBUG', False)
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
...
Update README.md
# Palindrome project
Project used to explain my view on a django project architecture
## Tools, libs, etc. Some time related files.
Versions on Poetry.
- [Python](https://www.python.org/) Programming languange
- [django-environ](https://django-environ.readthedocs.io) Manage .envs in Django
- [Poetry](https://python-poetry.org/) Python packaging and dependency management
- poetry.lock
- pyproject.toml
- [Django](https://www.djangoproject.com/) Web framework written in Python
- [Docker](https://www.docker.com/) Manage containers for dev environment
- compose.yaml
- compose/dev/Dockerfile
- compose/dev/start
- .env
- [Just](https://just.systems/) encapsulate commands for easier use
- justfile
## Dev environment setup
1. Install Just, Docker and Poetry(opcional).
2. Copy .env.example to .env, no need for edition.
3. Certified that docker is up and running
4. $ just build
## Run the server for development
1. Certified that docker is up and running
2. $ just runserver
You can access on http://0.0.0.0:8000/
Build and run
Well, with your docker running and everything setup, we can now go to part 2: Postgres, configure Postgres on settings, docker etc.
Good luck and remember what happened in 1971.
Posted on September 30, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.