Package Installation Not working with uv, ModuleNotFoundError: No module named 'rest_framework'
Hi,
Steps to Recreate:
- Initialize a project using cookiecutter.
- Choose docker as yes
- build and run the project, it will work
- add a new package in the pyproject.toml (eg:djangorestframework)
- run docker compose -f docker-compose.local.yml run --rm django uv lock
- build the image again
- run the container, it will work.
- Now go into the config/settings/base.py file and put "rest_framework", inside THIRD_PARTY_APPS.
- build the image
- run the container, you will see error. ModuleNotFoundError: No module named 'rest_framework'I installed rest framework just for dummy, I know we can directly install it from the cookiecutter, in all of my recent projects with cookiecutter , whenever I try to use a new package it doesn't work. Seems like it's not getting installed inside the environment. In the 6th step when I went into the bash of the container and did pip freeze it did not showed rest_framework, so I knew that it will fail in the 7,8 and 9 steps.
Seems like some issue with the docker compose / docker file . Not sure exactly about it.
Earlier when pip was being used to install packages it was working like them. Here are the details.
My configurations:
Machine: Macbook Pro Chip: Apple M3 Max Memory: 48 GB macOS: Tahoe 26.0
Docker version 28.5.1, build e180ab8 docker desktop: 4.48.0 (207573)
cookie-cutter version(maybe latest): 11 Oct 2025 2:44 pm from here: cookiecutter gh:cookiecutter/cookiecutter-django . And chose when prompted to download the latest.
Dockerfile ###################################################################################################### `# define an alias for the specific python version used in this file. FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS python
Python build stage
FROM python AS python-build-stage
ARG APP_HOME=/app
WORKDIR ${APP_HOME}
we need to move the virtualenv outside of the $APP_HOME directory because it will be overriden by the docker compose mount
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=0
Install apt packages
RUN apt-get update && apt-get install --no-install-recommends -y \
dependencies for building Python packages
build-essential \
psycopg dependencies
libpq-dev
gettext
wait-for-it
Requirements are installed here to ensure they will be cached.
RUN --mount=type=cache,target=/root/.cache/uv
--mount=type=bind,source=pyproject.toml,target=pyproject.toml
--mount=type=bind,source=uv.lock,target=uv.lock:rw
uv sync --no-install-project
COPY . ${APP_HOME}
RUN --mount=type=cache,target=/root/.cache/uv
--mount=type=bind,source=pyproject.toml,target=pyproject.toml
--mount=type=bind,source=uv.lock,target=uv.lock:rw
uv sync
devcontainer dependencies and utils
RUN apt-get update && apt-get install --no-install-recommends -y
sudo git bash-completion nano ssh
Create devcontainer user and add it to sudoers
RUN groupadd --gid 1000 dev-user
&& useradd --uid 1000 --gid dev-user --shell /bin/bash --create-home dev-user
&& echo dev-user ALL=(root) NOPASSWD:ALL > /etc/sudoers.d/dev-user
&& chmod 0440 /etc/sudoers.d/dev-user
ENV PATH="/${APP_HOME}/.venv/bin:$PATH" ENV PYTHONPATH="${APP_HOME}/.venv/lib/python3.13/site-packages:$PYTHONPATH"
COPY ./compose/production/django/entrypoint /entrypoint RUN sed -i 's/\r$//g' /entrypoint RUN chmod +x /entrypoint
COPY ./compose/local/django/start /start RUN sed -i 's/\r$//g' /start RUN chmod +x /start
ENTRYPOINT ["/entrypoint"] ` ######################################################################################################
docker-compose.local.yml file ###################################################################################################### `volumes: my_awesome_project_local_postgres_data: {} my_awesome_project_local_postgres_data_backups: {}
services: django: build: context: . dockerfile: ./compose/local/django/Dockerfile image: my_awesome_project_local_django container_name: my_awesome_project_local_django depends_on: - postgres volumes: - /app/.venv - .:/app:z env_file: - ./.envs/.local/.django - ./.envs/.local/.postgres ports: - '8000:8000' command: /start
postgres: build: context: . dockerfile: ./compose/production/postgres/Dockerfile image: my_awesome_project_production_postgres container_name: my_awesome_project_local_postgres volumes: - my_awesome_project_local_postgres_data:/var/lib/postgresql/data - my_awesome_project_local_postgres_data_backups:/backups env_file: - ./.envs/.local/.postgres ` ######################################################################################################
pyproject.toml
###################################################################################################### `# ==== pytest ==== [tool.pytest.ini_options] minversion = "6.0" addopts = "--ds=config.settings.test --reuse-db --import-mode=importlib" python_files = [ "tests.py", "test_*.py", ]
==== Coverage ====
[tool.coverage.run] include = ["my_awesome_project/**"] omit = ["/migrations/", "/tests/"] plugins = ["django_coverage_plugin"]
==== mypy ====
[tool.mypy] python_version = "3.13" check_untyped_defs = true ignore_missing_imports = true warn_unused_ignores = true warn_redundant_casts = true warn_unused_configs = true plugins = [ "mypy_django_plugin.main", ]
[[tool.mypy.overrides]]
Django migrations should not produce any errors:
module = ".migrations." ignore_errors = true
[tool.django-stubs] django_settings_module = "config.settings.test"
==== djLint ====
[tool.djlint] blank_line_after_tag = "load,extends" close_void_tags = true format_css = true format_js = true
TODO: remove T002 when fixed https://github.com/djlint/djLint/issues/687
ignore = "H006,H030,H031,T002" include = "H017,H035" indent = 2 max_line_length = 119 profile = "django"
[tool.djlint.css] indent_size = 2
[tool.djlint.js] indent_size = 2
[tool.ruff]
Exclude a variety of commonly ignored directories.
extend-exclude = [ "/migrations/.py", "staticfiles/*", ]
[tool.ruff.lint]
select = [
"F",
"E",
"W",
"C90",
"I",
"N",
"UP",
"YTT",
# "ANN", # flake8-annotations: we should support this in the future but 100+ errors atm
"ASYNC",
"S",
"BLE",
"FBT",
"B",
"A",
"COM",
"C4",
"DTZ",
"T10",
"DJ",
"EM",
"EXE",
"FA",
'ISC',
"ICN",
"G",
'INP',
'PIE',
"T20",
'PYI',
'PT',
"Q",
"RSE",
"RET",
"SLF",
"SLOT",
"SIM",
"TID",
"TC",
"INT",
# "ARG", # Unused function argument
"PTH",
"ERA",
"PD",
"PGH",
"PL",
"TRY",
"FLY",
# "NPY",
# "AIR",
"PERF",
# "FURB",
# "LOG",
"RUF",
]
ignore = [
"S101", # Use of assert detected https://docs.astral.sh/ruff/rules/assert/
"RUF012", # Mutable class attributes should be annotated with typing.ClassVar
"SIM102", # sometimes it's better to nest
# of types for comparison.
# Deactivated because it can make the code slow:
# https://github.com/astral-sh/ruff/issues/7871
]
[tool.ruff.lint.isort] force-single-line = true
[dependency-groups] dev = [ "coverage==7.10.7", "django-coverage-plugin==3.2.0", "django-debug-toolbar==6.0.0", "django-extensions==4.1", "django-stubs[compatible-mypy]==5.2.7", "djlint==1.36.4", "factory-boy==3.3.2", "ipdb==0.13.13", "mypy==1.18.2", "pre-commit==4.3.0", "psycopg[c]==3.2.10", "pytest==8.4.2", "pytest-django==4.11.1", "pytest-sugar==1.1.1", "ruff==0.14.0", "sphinx==8.2.3", "sphinx-autobuild==2025.8.25", "werkzeug[watchdog]==3.1.3", ]
[project] name = "my_awesome_project" version = "0.1.0" description = "Behold My Awesome Project!" readme = "README.md"
license = { text = "MIT" } authors = [ { name = "Daniel Roy Greenfeld", email = "[email protected]" }, ] requires-python = "==3.13.*" dependencies = [ "argon2-cffi==25.1.0", "collectfasta==3.3.1", "crispy-bootstrap5==2025.6", "django==5.2.7", "django-allauth[mfa]==65.12.0", "django-anymail[mailgun]==13.1", "django-crispy-forms==2.4", "django-environ==0.12.0", "django-model-utils==5.0.0", "django-redis==6.0.0", "django-storages[s3]==1.14.6", "gunicorn==23.0.0", "hiredis==3.2.1", "pillow==11.3.0", "psycopg[c]==3.2.10", "python-slugify==8.0.4", "redis==6.4.0", "djangorestframework==3.16.1" ] `
Source: cookiecutter/cookiecutter-django