diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..cbcd4eca --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.venv +Dockerfile +.idea +docker-compose.yml diff --git a/.gitignore b/.gitignore index 0b1609c6..6eca078d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ *.iml .env .DS_Store -venv/ +.venv/ .pytest_cache/ **__pycache__/ **db.sqlite3 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..974561b6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.12-alpine +LABEL maintainer="dmitriykuzmin@ymail.com" + +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +COPY requirements.txt requirements.txt +RUN pip install --no-cache-dir -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 /app +RUN chmod -R 755 /files/media/ + +USER my_user diff --git a/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py b/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py new file mode 100644 index 00000000..c41368ec --- /dev/null +++ b/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 5.2.12 on 2026-03-31 10:55 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cinema', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name='movie', + name='actors', + field=models.ManyToManyField(blank=True, related_name='movies', to='cinema.actor'), + ), + migrations.AlterField( + model_name='movie', + name='genres', + field=models.ManyToManyField(blank=True, related_name='movies', to='cinema.genre'), + ), + migrations.AlterField( + model_name='moviesession', + name='cinema_hall', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.cinemahall'), + ), + migrations.AlterField( + model_name='moviesession', + name='movie', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.movie'), + ), + migrations.AlterField( + model_name='order', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 90dde772..cf3ef92e 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -9,6 +9,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ +import os from datetime import timedelta from pathlib import Path @@ -27,7 +28,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["0.0.0.0", "127.0.0.1", "localhost"] INTERNAL_IPS = [ "127.0.0.1", @@ -47,6 +48,7 @@ "debug_toolbar", "cinema", "user", + "core", ] MIDDLEWARE = [ @@ -86,12 +88,15 @@ DATABASES = { "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", + "ENGINE": "django.db.backends.postgresql", + "NAME": os.environ.get("POSTGRES_DB"), + "USER": os.environ.get("POSTGRES_USER"), + "PASSWORD": os.environ.get("POSTGRES_PASSWORD"), + "HOST": os.environ.get("POSTGRES_HOST"), + "PORT": os.environ.get("POSTGRES_PORT"), } } - # Password validation # https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators @@ -134,7 +139,7 @@ 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/core/__init__.py b/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/core/admin.py b/core/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/core/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/core/apps.py b/core/apps.py new file mode 100644 index 00000000..c0ce093b --- /dev/null +++ b/core/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "core" diff --git a/core/management/__init__.py b/core/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/core/management/commands/__init__.py b/core/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/core/management/commands/wait_for_db.py b/core/management/commands/wait_for_db.py new file mode 100644 index 00000000..f91fefa2 --- /dev/null +++ b/core/management/commands/wait_for_db.py @@ -0,0 +1,21 @@ +import time + +from django.db import connections +from django.db.utils import OperationalError +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + """Django command to pause execution until database is available""" + + def handle(self, *args, **kwargs): + self.stdout.write("Waiting for database...") + while True: + try: + db = connections["default"] + db.ensure_connection() + break + except OperationalError: + self.stdout.write("Database unavailable, waiting 1 second...") + time.sleep(1) + self.stdout.write(self.style.SUCCESS("Database available")) diff --git a/core/migrations/__init__.py b/core/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/core/models.py b/core/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/core/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/core/tests.py b/core/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/core/views.py b/core/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/core/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..89fa23b7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +services: + app: + build: + context: . + ports: + - "8000:8000" + volumes: + - ./:/app/ + - my_media:/files/media + command: > + sh -c "python manage.py wait_for_db && + python manage.py migrate && + python manage.py runserver 0.0.0.0:8000" + env_file: + - .env + depends_on: + - db + + db: + image: postgres:14-alpine + ports: + - "5432:5432" + env_file: + - .env + restart: always + volumes: + - my_db:/var/lib/postgresql/data + +volumes: + my_db: + my_media: diff --git a/requirements.txt b/requirements.txt index 2dc12c67..ceef6e30 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,5 @@ djangorestframework djangorestframework-simplejwt drf-spectacular Pillow +psycopg==3.1.12 +psycopg-binary==3.1.12