couldn't import Django from console

File “/code/manage.py”, line 8, in
from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named ‘django’

I just launched my first django app on the platform. It’s running, but I need to run a couple manage commands.
I checked to make sure no critical django files were included in dockerignore or gitignore

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File “/code/manage.py”, line 10, in
raise ImportError(
ImportError: Couldn’t import Django. Are you sure it’s installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?

here’s my dockerfile. it seems to reference a .venv directory, but none exists when I connect via fly ssh console.

syntax = docker/dockerfile:1.5

Multi-stage Docker buildfile

See Multi-stage | Docker Docs

Stage 1: Build the python dependencies

FROM python:3.12-slim-bookworm as build-python

This approximately follows this guide: Production-ready Python Docker Containers with uv

Which creates a standalone environment with the dependencies.

- Silence uv complaining about not being able to use hard links,

- tell uv to byte-compile packages for faster application startups,

- prevent uv from accidentally downloading isolated Python builds,

- pick a Python (use /usr/bin/python3.12 on uv 0.5.0 and later),

- and finally declare /app as the target for uv sync.

ENV UV_LINK_MODE=copy
UV_COMPILE_BYTECODE=1
UV_PYTHON_DOWNLOADS=never
UV_PROJECT_ENVIRONMENT=/code/.venv

COPY --from=Package uv · GitHub /uv /uvx /bin/

Since there’s no point in shipping lock files, we move them

into a directory that is NOT copied into the runtime image.

The trailing slash makes COPY create /_lock/ automagically.

COPY pyproject.toml uv.lock /_lock/

Synchronize dependencies.

This layer is cached until uv.lock or pyproject.toml change.

RUN --mount=type=cache,target=/root/.cache
cd /_lock &&
uv sync
–frozen
–no-group dev
–group prod

Stage 2: Build the front end files

FROM node:22-bookworm-slim AS build-node
RUN nodejs -v && npm -v
WORKDIR /code
COPY *.json *.js .babelrc /code/
COPY assets /code/assets/
COPY api-client /code/api-client/

RUN npm install

build needs everything because it needs to be able to do the tailwind class detection / purging stuff

COPY . /code
RUN npm run build

Stage 3: Build the final image

This copies the python dependencies from the first stage

and the front end files from the second stage.

Add any runtime OS dependencies here.

FROM python:3.12-slim-bookworm
ENV PYTHONUNBUFFERED=1
ENV DEBUG=0

RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked
–mount=target=/var/cache/apt,type=cache,sharing=locked
rm -f /etc/apt/apt.conf.d/docker-clean &&
apt-get update
&& apt-get install -y
curl
# psycopg2 dependencies
libpq-dev
# Translations dependencies
gettext
# cleaning up unused files
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false

RUN addgroup --system django
&& adduser --system --ingroup django django

WORKDIR /code
COPY --from=build-python --chown=django:django /code /code

make sure we use the virtualenv python and other binaries by default

ENV PATH=“/code/.venv/bin:$PATH”

COPY --chown=django:django . /code
COPY --from=build-node /code/static /code/static

why this has to be here:

Where to run collectstatic when deploying django app to heroku using docker? - Stack Overflow

RUN DEBUG=False python /code/manage.py collectstatic --noinput --settings=mealitopia.settings_production
RUN chown django:django -R static_root

USER django

Run gunicorn by default

CMD exec gunicorn --bind 0.0.0.0:8080 --workers 1 --threads 8 --timeout 0 mealitopia.asgi:application -k uvicorn.workers.UvicornWorker

Can you login to your app with fly ssh console and then run which python and echo $PATH?

It seems like for some reason it’s not using the same python as your app process, though it’s unclear why that would be happening.

Tip: use Markdown for readability if you can. For code, you can use this backtick format:

```
Paste code here
```