Django + Poetry + Docker
Nathan Clement · September 8, 2026 · 4 min read
Nathan Clement · September 8, 2026 · 4 min read
Managing Python packages for Django made delightful

Photo by Patrick Tomasso on Unsplash
A new developer might start building a Django site by installing the latest version of Python from python.org, and using pip to install any necessary packages. Once local development is complete, they may deploy their code to a server prebuilt to host Python applications, only to see an Exception: Import Error: No module named django
This happens because no one installed Django on the host server.
To avoid this issue, they could define all imports in a Dockerfile. Something like this would work:
# ./Dockerfile
# pull official base image
FROM python:3.11-alpine
# set work directory
# set environment variables
# install linux dependencies
# install python dependencies
pip3 install -U pip
pip3 install Django=4.1.5
pip3 install some-package=1.0.0
pip3 install another-package=1.0.0
# copy project
# expose port
# run start command
This becomes painful to manage as soon as they start installing more dependencies, since they must carefully ensure that all local packages precisely match those in the Dockerfile.
If they start building another project that needs a different version of Python, or a different version of a package, the difficulty grows rapidly.
Several systems have grown within the Python ecosystem to alleviate the pain of package management complexity.
One of the most commonly referenced ways to manage Python packages and environments is to use the standard venv module.
This article does a great job explaining what Virtual Environments are in Python, and how to use them: https://realpython.com/python-virtual-environments-a-primer/
Virtual environments work great, but can also lead to frustration:
requirements.txt — which can make upgrades less clear.pip freeze > requirements.txtrequirements.txt includes all dependencies for your installed packages, it can be difficult to clean out a package that is no longer being used.Poetry manages the creation of virtual environments in a way that I have found both powerful and delightful.
Some highlights:
pyproject.toml and poetry.lock manage your environment in a way that feels similar to package.json and package.lock.json in Node.jsnpmpyproject.toml filepoetry run python script.pyImagine you have a simple Django application that you want to deploy as a Docker container, managed by Poetry.
curl -sSL https://install.python-poetry.org | python3 -zsh so I added the following to my .zshrc file: export PATH=”$PATH:/$HOME/.local/bin”poetry init — you can use the CLI prompts to interactively set up your dependencies, or add the later yourselfpoetry add Django)poetry run python manage.py runserver )Here is an example working Dockerfile:
# ./Dockerfile
# pull official base image
FROM python:3.11-alpine
# set work directory
WORKDIR /app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1s
# install linux dependencies
# these may vary by project
# this list is relatively lightweight
# and it handles most of what I need
RUN apk update && apk upgrade && \
apk add --no-cache gcc g++ musl-dev curl libffi-dev postgresql-dev zlib-dev jpeg-dev freetype-dev
# install poetry to manage python dependencies
RUN curl -sSL https://install.python-poetry.org | python3 -
# install python dependencies
COPY ./pyproject.toml .
COPY ./poetry.lock .
RUN /root/.local/bin/poetry install
# copy project
COPY . .
# run at port 8000
EXPOSE 8000
CMD /app/scripts/start_server.sh
This script starts the Django server (per the Dockerfile above, I store it at ./scripts/start_server.sh
/root/.local/bin/poetry run python manage.py runserver 0.0.0.0:8000
In this case, /root/.local/bin/poetry lets me avoid adding poetry to the PATH in my container.
Deploy this container, and you are off to the races!
Let me know what you think about this approach, and if you see the benefit of a tool like Poetry, or if you have a different preferred Python package management strategy!
Originally published on 2023-01-31 on Medium.