From 063ca85f98029b51f22259dbf460ec08f04b6c7d Mon Sep 17 00:00:00 2001 From: Olha Yukhnenko Date: Fri, 22 May 2026 20:46:14 +0300 Subject: [PATCH 1/3] solved task --- .dockerignore | 20 +++++++++++++++ .gitignore | 7 ++++- Dockerfile | 23 +++++++++++++++++ cinema/management/__init__.py | 0 cinema/management/commands/__init__.py | 0 cinema/management/commands/wait_for_db.py | 26 +++++++++++++++++++ cinema_service/settings.py | 19 +++++++++----- docker-compose.yml | 31 +++++++++++++++++++++++ requirements.txt | 4 +++ 9 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 cinema/management/__init__.py create mode 100644 cinema/management/commands/__init__.py create mode 100644 cinema/management/commands/wait_for_db.py create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..b2db1d27 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,20 @@ +.idea/ +.vscode/ +*.iml +.DS_Store +.env +venv/ +.pytest_cache/ +**__pycache__/ +*.pyc +**db.sqlite3 +media/ +.venv/ +Dockerfile +.git +.gitignore +backups +*.log +tmp +docker-compose.yml +logs/ diff --git a/.gitignore b/.gitignore index 0b1609c6..b32a60cc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,10 @@ venv/ .pytest_cache/ **__pycache__/ +*.pyc **db.sqlite3 -media +media/ +.venv/ +staticfiles/ +*.log +logs/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..3cd6b6bf --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.11.15-alpine3.22 + +LABEL maintainer="yukhnenko.o@gmail.com" + +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +COPY requirements.txt requirements.txt +RUN pip install -r requirements.txt + +COPY . . +RUN mkdir -p /files/media + +RUN adduser \ + --disabled-password \ + --no-create-home \ + my_user + +RUN chown -R my_user /files/media +RUN chmod -R 755 /files/media + +USER my_user diff --git a/cinema/management/__init__.py b/cinema/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cinema/management/commands/__init__.py b/cinema/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cinema/management/commands/wait_for_db.py b/cinema/management/commands/wait_for_db.py new file mode 100644 index 00000000..48c2db50 --- /dev/null +++ b/cinema/management/commands/wait_for_db.py @@ -0,0 +1,26 @@ +from django.core.management.base import BaseCommand +from django.db import connections +from django.db.utils import OperationalError +import time + + +class Command(BaseCommand): + """Django command to pause execution until database is available""" + + def handle(self, *args, **options): + self.stdout.write("Waiting for database...", ending="") + + db_conn = None + + while not db_conn: + try: + db_conn = connections["default"] + self.stdout.write( + "Database unavailable, waiting for a 1 second", + ending="" + ) + db_conn.cursor() + except OperationalError: + time.sleep(1) + + self.stdout.write(self.style.SUCCESS("Database available!")) diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 90dde772..8e0cfeb9 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -9,9 +9,13 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ +import os +from dotenv import load_dotenv from datetime import timedelta from pathlib import Path +load_dotenv() + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -20,9 +24,7 @@ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = ( - "django-insecure-6vubhk2$++agnctay_4pxy_8cq)mosmn(*-#2b^v4cgsh-^!i3" -) +SECRET_KEY = os.getenv("DJANGO_SECRET_KEY") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -86,8 +88,12 @@ DATABASES = { "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", + "ENGINE": "django.db.backends.postgresql", + "NAME": os.environ["POSTGRES_DB"], + "USER": os.environ["POSTGRES_USER"], + "PASSWORD": os.environ["POSTGRES_PASSWORD"], + "HOST": os.environ["POSTGRES_HOST"], + "PORT": os.environ["POSTGRES_PORT"], } } @@ -132,9 +138,8 @@ # https://docs.djangoproject.com/en/4.0/howto/static-files/ STATIC_URL = "static/" - MEDIA_URL = "/media/" -MEDIA_ROOT = BASE_DIR / "media" +MEDIA_ROOT = "/files/media" # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..e749bb38 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +services: + cinema: + build: + context: . + env_file: + - .env + ports: + - "8000:8000" + command: > + sh -c "python manage.py wait_for_db && + python manage.py migrate && + python manage.py runserver 0.0.0.0:8000" + volumes: + - my_media:/files/media + depends_on: + - db + + + db: + image: postgres:16-alpine3.22 + restart: always + env_file: + - .env + ports: + - "5432:5432" + volumes: + - my_db:$PGDATA + +volumes: + my_db: + my_media: diff --git a/requirements.txt b/requirements.txt index 2dc12c67..36460a5a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,7 @@ djangorestframework djangorestframework-simplejwt drf-spectacular Pillow +python-dotenv +psycopg +psycopg-binary + From 44858dc80016882df5db82deabf7f0bd5f019853 Mon Sep 17 00:00:00 2001 From: Olha Yukhnenko Date: Fri, 22 May 2026 23:23:32 +0300 Subject: [PATCH 2/3] solved task --- cinema/management/commands/wait_for_db.py | 17 ++++++++++++----- docker-compose.yml | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cinema/management/commands/wait_for_db.py b/cinema/management/commands/wait_for_db.py index 48c2db50..f55773f4 100644 --- a/cinema/management/commands/wait_for_db.py +++ b/cinema/management/commands/wait_for_db.py @@ -10,17 +10,24 @@ class Command(BaseCommand): def handle(self, *args, **options): self.stdout.write("Waiting for database...", ending="") - db_conn = None + attempts = 0 + max_attempts = 30 + db_ready = False - while not db_conn: + while attempts < max_attempts: try: - db_conn = connections["default"] + connections["default"].cursor() + db_ready = True + break + except OperationalError: self.stdout.write( "Database unavailable, waiting for a 1 second", ending="" ) - db_conn.cursor() - except OperationalError: + attempts += 1 time.sleep(1) + if not db_ready: + raise Exception("Database not available after max attempts") + self.stdout.write(self.style.SUCCESS("Database available!")) diff --git a/docker-compose.yml b/docker-compose.yml index e749bb38..3cae6bf6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ services: - cinema: + app: build: context: . env_file: @@ -24,7 +24,7 @@ services: ports: - "5432:5432" volumes: - - my_db:$PGDATA + - my_db:/var/lib/postgresql/data volumes: my_db: From 4394231a1bdbcc7325c0d653695538a66f6d0b0a Mon Sep 17 00:00:00 2001 From: Olha Yukhnenko Date: Mon, 25 May 2026 12:22:13 +0300 Subject: [PATCH 3/3] added command python manage.py collectstatic --noinput to the docker-compose file, added STATIC_ROOT to the settings module and created directory /app/staticfiles with chown and chmod rights for user in dockerfile --- Dockerfile | 5 +++-- cinema_service/settings.py | 3 ++- docker-compose.yml | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3cd6b6bf..851b34b5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,13 +11,14 @@ RUN pip install -r requirements.txt COPY . . RUN mkdir -p /files/media +RUN mkdir -p /app/staticfiles RUN adduser \ --disabled-password \ --no-create-home \ my_user -RUN chown -R my_user /files/media -RUN chmod -R 755 /files/media +RUN chown -R my_user /files/media /app/staticfiles +RUN chmod -R 755 /files/media /app/staticfiles USER my_user diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 8e0cfeb9..c037e1c6 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -136,8 +136,9 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.0/howto/static-files/ +STATIC_ROOT = BASE_DIR / "staticfiles" +STATIC_URL = "/static/" -STATIC_URL = "static/" MEDIA_URL = "/media/" MEDIA_ROOT = "/files/media" diff --git a/docker-compose.yml b/docker-compose.yml index 3cae6bf6..2e4a50c3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,13 +9,13 @@ services: command: > sh -c "python manage.py wait_for_db && python manage.py migrate && + python manage.py collectstatic --noinput && python manage.py runserver 0.0.0.0:8000" volumes: - my_media:/files/media depends_on: - db - db: image: postgres:16-alpine3.22 restart: always