From f7377f7bf0b3152d4f89c11a8e970fbe735154ee Mon Sep 17 00:00:00 2001 From: Ruslan Date: Fri, 17 Apr 2026 14:15:40 +0300 Subject: [PATCH 1/5] Solution --- .dockerignore | 4 ++ Dockerfile | 23 +++++++++++ cinema/management/__init__.py | 0 cinema/management/commands/__init__.py | 0 cinema/management/commands/wait_for_db.py | 19 +++++++++ ...ovie_actors_alter_movie_genres_and_more.py | 41 +++++++++++++++++++ cinema_service/settings.py | 15 ++++--- docker-compose.yaml | 33 +++++++++++++++ requirements.txt | 2 + 9 files changed, 132 insertions(+), 5 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 cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py create mode 100644 docker-compose.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..56df531a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.venv +Dockerfile +.idea +docker-compose.yaml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..8f50e9cc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.11.6-alpine3.18 + +LABEL maintainer="rarturus" + +ENV PYTHONUNBUFFERED 1 + +WORKDIR /app + +COPY 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 +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..190fa8b7 --- /dev/null +++ b/cinema/management/commands/wait_for_db.py @@ -0,0 +1,19 @@ +import time +from django.core.management.base import BaseCommand +from django.db import connections +from django.db.utils import OperationalError + + +class Command(BaseCommand): + help1 = "Wait for database to be available" + + def handle(self, *args, **options): + self.stdout.write("Waiting for database...") + while True: + try: + connections["default"].cursor() + 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/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..e370eb93 --- /dev/null +++ b/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 6.0.4 on 2026-04-16 22:41 + +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..540b3e92 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 @@ -86,12 +87,15 @@ DATABASES = { "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", + "ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"), + "NAME": os.environ.get("SQL_DATABASE", BASE_DIR / "db.sqlite3"), + "USER": os.environ.get("SQL_USER", "user"), + "PASSWORD": os.environ.get("SQL_PASSWORD", "password"), + "HOST": os.environ.get("SQL_HOST", "localhost"), + "PORT": os.environ.get("SQL_PORT", "5432"), } } - # Password validation # https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators @@ -134,7 +138,8 @@ 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 @@ -167,7 +172,7 @@ } SIMPLE_JWT = { - "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), + "ACCESS_TOKEN_LIFETIME": timedelta(days=1), "REFRESH_TOKEN_LIFETIME": timedelta(days=1), "ROTATE_REFRESH_TOKENS": False, } diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..6226dc7a --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,33 @@ +services: + cinema: + build: + context: . + env_file: + - .env + command: > + sh -c "python manage.py wait_for_db && python manage.py migrate && + python manage.py runserver 0.0.0.0:8000" + volumes: + - ./:/app + - media_data:/files/media + depends_on: + - db + + db: + image: postgres:16.0-alpine3.17 + environment: + POSTGRES_USER: "rarturus" + POSTGRES_PASSWORD: "password" + POSTGRES_DB: "db" + restart: always + ports: + - "5432:5432" + env_file: + - .env + volumes: + - db_data:$PG_DATA + + +volumes: + db_data: + media_data: diff --git a/requirements.txt b/requirements.txt index 2dc12c67..60af6ce3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,5 @@ djangorestframework djangorestframework-simplejwt drf-spectacular Pillow +psycopg==3.3.3 +psycopg-binary==3.3.3 From 7df48dd9b4882a79318797f2d977f9a6489e871b Mon Sep 17 00:00:00 2001 From: Ruslan Date: Fri, 17 Apr 2026 15:04:43 +0300 Subject: [PATCH 2/5] Solution --- .dockerignore | 8 ++++++-- Dockerfile | 4 +--- cinema/management/commands/wait_for_db.py | 2 +- cinema_service/settings.py | 2 +- docker-compose.yaml => docker-compose.yml | 5 +++-- 5 files changed, 12 insertions(+), 9 deletions(-) rename docker-compose.yaml => docker-compose.yml (88%) diff --git a/.dockerignore b/.dockerignore index 56df531a..01f8eb3f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,8 @@ .venv -Dockerfile +.env +__pycache__/ +*.pyc .idea -docker-compose.yaml +docker-compose.yml +media +.pytest_cache/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8f50e9cc..708c1b7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11.6-alpine3.18 +FROM python:3.11-slim LABEL maintainer="rarturus" @@ -19,5 +19,3 @@ RUN adduser \ RUN chown -R my_user /files/media RUN chmod -R 755 /files/media - -USER my_user diff --git a/cinema/management/commands/wait_for_db.py b/cinema/management/commands/wait_for_db.py index 190fa8b7..5c74fe69 100644 --- a/cinema/management/commands/wait_for_db.py +++ b/cinema/management/commands/wait_for_db.py @@ -5,7 +5,7 @@ class Command(BaseCommand): - help1 = "Wait for database to be available" + help = "Wait for database to be available" def handle(self, *args, **options): self.stdout.write("Waiting for database...") diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 540b3e92..c3aa6a93 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -138,7 +138,7 @@ STATIC_URL = "static/" MEDIA_URL = "/media/" -MEDIA_ROOT = "files/media" +MEDIA_ROOT = "/files/media" # Default primary key field type diff --git a/docker-compose.yaml b/docker-compose.yml similarity index 88% rename from docker-compose.yaml rename to docker-compose.yml index 6226dc7a..3c9d3669 100644 --- a/docker-compose.yaml +++ b/docker-compose.yml @@ -8,10 +8,11 @@ services: sh -c "python manage.py wait_for_db && python manage.py migrate && python manage.py runserver 0.0.0.0:8000" volumes: - - ./:/app - media_data:/files/media depends_on: - db + ports: + - "8000:8000" db: image: postgres:16.0-alpine3.17 @@ -25,7 +26,7 @@ services: env_file: - .env volumes: - - db_data:$PG_DATA + - db_data:/var/lib/postgresql/data volumes: From 625ed8e25eb38bd3a2f7ad57396b26e58db58248 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Fri, 17 Apr 2026 15:54:35 +0300 Subject: [PATCH 3/5] Solution --- .dockerignore | 1 - Dockerfile | 4 +- cinema/migrations/0001_initial.py | 194 ------------------ ...ovie_actors_alter_movie_genres_and_more.py | 41 ---- docker-compose.yml | 2 +- user/migrations/0001_initial.py | 138 ------------- ..._managers_remove_user_username_and_more.py | 31 --- 7 files changed, 4 insertions(+), 407 deletions(-) delete mode 100644 cinema/migrations/0001_initial.py delete mode 100644 cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py delete mode 100644 user/migrations/0001_initial.py delete mode 100644 user/migrations/0002_alter_user_managers_remove_user_username_and_more.py diff --git a/.dockerignore b/.dockerignore index 01f8eb3f..5634ae17 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,6 +3,5 @@ __pycache__/ *.pyc .idea -docker-compose.yml media .pytest_cache/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 708c1b7a..c47e9387 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,5 +17,7 @@ RUN adduser \ --no-create-home \ my_user -RUN chown -R my_user /files/media +RUN chown -R my_user:my_user /app RUN chmod -R 755 /files/media + +USER my_user diff --git a/cinema/migrations/0001_initial.py b/cinema/migrations/0001_initial.py deleted file mode 100644 index 9a4ce64b..00000000 --- a/cinema/migrations/0001_initial.py +++ /dev/null @@ -1,194 +0,0 @@ -# Generated by Django 4.0.4 on 2022-06-14 12:26 - -import cinema.models -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name="Actor", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("first_name", models.CharField(max_length=255)), - ("last_name", models.CharField(max_length=255)), - ], - ), - migrations.CreateModel( - name="CinemaHall", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.CharField(max_length=255)), - ("rows", models.IntegerField()), - ("seats_in_row", models.IntegerField()), - ], - ), - migrations.CreateModel( - name="Genre", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.CharField(max_length=255, unique=True)), - ], - ), - migrations.CreateModel( - name="Movie", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("title", models.CharField(max_length=255)), - ("description", models.TextField()), - ("duration", models.IntegerField()), - ( - "image", - models.ImageField( - null=True, - upload_to=cinema.models.movie_image_file_path, - ), - ), - ( - "actors", - models.ManyToManyField(blank=True, to="cinema.actor"), - ), - ( - "genres", - models.ManyToManyField(blank=True, to="cinema.genre"), - ), - ], - options={ - "ordering": ["title"], - }, - ), - migrations.CreateModel( - name="MovieSession", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("show_time", models.DateTimeField()), - ( - "cinema_hall", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="cinema.cinemahall", - ), - ), - ( - "movie", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="cinema.movie", - ), - ), - ], - options={ - "ordering": ["-show_time"], - }, - ), - migrations.CreateModel( - name="Order", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "ordering": ["-created_at"], - }, - ), - migrations.CreateModel( - name="Ticket", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("row", models.IntegerField()), - ("seat", models.IntegerField()), - ( - "movie_session", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="tickets", - to="cinema.moviesession", - ), - ), - ( - "order", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="tickets", - to="cinema.order", - ), - ), - ], - options={ - "ordering": ["row", "seat"], - "unique_together": {("movie_session", "row", "seat")}, - }, - ), - ] 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 deleted file mode 100644 index e370eb93..00000000 --- a/cinema/migrations/0002_alter_movie_actors_alter_movie_genres_and_more.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 6.0.4 on 2026-04-16 22:41 - -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/docker-compose.yml b/docker-compose.yml index 3c9d3669..a432af78 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ services: - cinema: + app: build: context: . env_file: diff --git a/user/migrations/0001_initial.py b/user/migrations/0001_initial.py deleted file mode 100644 index c11bcb14..00000000 --- a/user/migrations/0001_initial.py +++ /dev/null @@ -1,138 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-10 11:54 - -import django.contrib.auth.models -import django.contrib.auth.validators -from django.db import migrations, models -import django.utils.timezone - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("auth", "0012_alter_user_first_name_max_length"), - ] - - operations = [ - migrations.CreateModel( - name="User", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "password", - models.CharField(max_length=128, verbose_name="password"), - ), - ( - "last_login", - models.DateTimeField( - blank=True, null=True, verbose_name="last login" - ), - ), - ( - "is_superuser", - models.BooleanField( - default=False, - help_text="Designates that this user has all permissions without explicitly assigning them.", - verbose_name="superuser status", - ), - ), - ( - "username", - models.CharField( - error_messages={ - "unique": "A user with that username already exists." - }, - help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", - max_length=150, - unique=True, - validators=[ - django.contrib.auth.validators.UnicodeUsernameValidator() - ], - verbose_name="username", - ), - ), - ( - "first_name", - models.CharField( - blank=True, max_length=150, verbose_name="first name" - ), - ), - ( - "last_name", - models.CharField( - blank=True, max_length=150, verbose_name="last name" - ), - ), - ( - "email", - models.EmailField( - blank=True, - max_length=254, - verbose_name="email address", - ), - ), - ( - "is_staff", - models.BooleanField( - default=False, - help_text="Designates whether the user can log into this admin site.", - verbose_name="staff status", - ), - ), - ( - "is_active", - models.BooleanField( - default=True, - help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", - verbose_name="active", - ), - ), - ( - "date_joined", - models.DateTimeField( - default=django.utils.timezone.now, - verbose_name="date joined", - ), - ), - ( - "groups", - models.ManyToManyField( - blank=True, - help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", - related_name="user_set", - related_query_name="user", - to="auth.group", - verbose_name="groups", - ), - ), - ( - "user_permissions", - models.ManyToManyField( - blank=True, - help_text="Specific permissions for this user.", - related_name="user_set", - related_query_name="user", - to="auth.permission", - verbose_name="user permissions", - ), - ), - ], - options={ - "verbose_name": "user", - "verbose_name_plural": "users", - "abstract": False, - }, - managers=[ - ("objects", django.contrib.auth.models.UserManager()), - ], - ), - ] diff --git a/user/migrations/0002_alter_user_managers_remove_user_username_and_more.py b/user/migrations/0002_alter_user_managers_remove_user_username_and_more.py deleted file mode 100644 index 66e2274f..00000000 --- a/user/migrations/0002_alter_user_managers_remove_user_username_and_more.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 4.0.4 on 2022-06-14 12:37 - -from django.db import migrations, models -import user.models - - -class Migration(migrations.Migration): - - dependencies = [ - ("user", "0001_initial"), - ] - - operations = [ - migrations.AlterModelManagers( - name="user", - managers=[ - ("objects", user.models.UserManager()), - ], - ), - migrations.RemoveField( - model_name="user", - name="username", - ), - migrations.AlterField( - model_name="user", - name="email", - field=models.EmailField( - max_length=254, unique=True, verbose_name="email address" - ), - ), - ] From 15438f90247ceb4864a64b0946e5c36beb4764a9 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Fri, 17 Apr 2026 16:06:42 +0300 Subject: [PATCH 4/5] Solution --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c47e9387..45c12656 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,8 @@ ENV PYTHONUNBUFFERED 1 WORKDIR /app COPY requirements.txt . + +RUN apt-get update && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/* RUN pip install --no-cache-dir -r requirements.txt COPY . . @@ -17,7 +19,7 @@ RUN adduser \ --no-create-home \ my_user -RUN chown -R my_user:my_user /app +RUN chown -R my_user:my_user /files/media RUN chmod -R 755 /files/media USER my_user From f8eb9267c399a4ae4256786443c17e9ddb36f3b0 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Tue, 28 Apr 2026 21:28:29 +0300 Subject: [PATCH 5/5] Solution --- cinema/management/commands/wait_for_db.py | 4 +- cinema/migrations/0001_initial.py | 94 +++++++++++++++++++++++ user/migrations/0001_initial.py | 42 ++++++++++ 3 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 cinema/migrations/0001_initial.py create mode 100644 user/migrations/0001_initial.py diff --git a/cinema/management/commands/wait_for_db.py b/cinema/management/commands/wait_for_db.py index 5c74fe69..209248e1 100644 --- a/cinema/management/commands/wait_for_db.py +++ b/cinema/management/commands/wait_for_db.py @@ -4,9 +4,7 @@ from django.db.utils import OperationalError -class Command(BaseCommand): - help = "Wait for database to be available" - +class WaitForDbCommand(BaseCommand): def handle(self, *args, **options): self.stdout.write("Waiting for database...") while True: diff --git a/cinema/migrations/0001_initial.py b/cinema/migrations/0001_initial.py new file mode 100644 index 00000000..e74ad8e1 --- /dev/null +++ b/cinema/migrations/0001_initial.py @@ -0,0 +1,94 @@ +# Generated by Django 6.0.4 on 2026-04-28 21:22 + +import cinema.models +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Actor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=255)), + ('last_name', models.CharField(max_length=255)), + ], + ), + migrations.CreateModel( + name='CinemaHall', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('rows', models.IntegerField()), + ('seats_in_row', models.IntegerField()), + ], + ), + migrations.CreateModel( + name='Genre', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, unique=True)), + ], + ), + migrations.CreateModel( + name='Movie', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('description', models.TextField()), + ('duration', models.IntegerField()), + ('image', models.ImageField(null=True, upload_to=cinema.models.movie_image_file_path)), + ('actors', models.ManyToManyField(blank=True, related_name='movies', to='cinema.actor')), + ('genres', models.ManyToManyField(blank=True, related_name='movies', to='cinema.genre')), + ], + options={ + 'ordering': ['title'], + }, + ), + migrations.CreateModel( + name='MovieSession', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('show_time', models.DateTimeField()), + ('cinema_hall', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.cinemahall')), + ('movie', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.movie')), + ], + options={ + 'ordering': ['-show_time'], + }, + ), + migrations.CreateModel( + name='Order', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['-created_at'], + }, + ), + migrations.CreateModel( + name='Ticket', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('row', models.IntegerField()), + ('seat', models.IntegerField()), + ('movie_session', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to='cinema.moviesession')), + ('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to='cinema.order')), + ], + options={ + 'ordering': ['row', 'seat'], + 'unique_together': {('movie_session', 'row', 'seat')}, + }, + ), + ] diff --git a/user/migrations/0001_initial.py b/user/migrations/0001_initial.py new file mode 100644 index 00000000..e4d415c1 --- /dev/null +++ b/user/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# Generated by Django 6.0.4 on 2026-04-28 21:22 + +import django.utils.timezone +import user.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', user.models.UserManager()), + ], + ), + ]