Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.venv
Dockerfile
.idea
docker-compose.yml
Comment on lines +1 to +4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good start for the .dockerignore file. To better align with the requirement to keep the image as thin as possible, consider adding other common patterns to this list. For example, you should ignore Python's cache directory (__pycache__/) and often the .gitignore file itself.

Comment on lines +1 to +4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is missing some important entries. To avoid including secrets and unnecessary files in your Docker image, it's a good practice to also ignore files like .env, media, __pycache__, and .pytest_cache. This helps fulfill the requirement to make your docker images as thin as possible.

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*.iml
.env
.DS_Store
venv/
.venv/
.pytest_cache/
**__pycache__/
**db.sqlite3
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern is not correct for ignoring the db.sqlite3 file. The ** glob in this context doesn't function as a recursive wildcard. To ignore the db.sqlite3 file at the root of the project, you can simply write db.sqlite3. If you want to ignore it in any subdirectory, the correct pattern would be **/db.sqlite3.

Expand Down
22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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
RUN chmod -R 755 /files/media/
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you've correctly set ownership for the media directory, the application code directory (/app) is still owned by root. When the application runs as my_user, this can lead to permission errors if it needs to write files (e.g., Python's .pyc cache files).

It's a good practice to also change the ownership of the app directory. Consider adding RUN chown -R my_user /app before the USER my_user instruction.


USER my_user
Original file line number Diff line number Diff line change
@@ -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),
),
]
15 changes: 10 additions & 5 deletions cinema_service/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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",
Expand All @@ -47,6 +48,7 @@
"debug_toolbar",
"cinema",
"user",
"core",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
Empty file added core/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions core/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions core/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class CoreConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "core"
Empty file added core/management/__init__.py
Empty file.
Empty file.
21 changes: 21 additions & 0 deletions core/management/commands/wait_for_db.py
Original file line number Diff line number Diff line change
@@ -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"))
Empty file added core/migrations/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions core/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
3 changes: 3 additions & 0 deletions core/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
3 changes: 3 additions & 0 deletions core/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.shortcuts import render

# Create your views here.
31 changes: 31 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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:$PGDATA
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of $PGDATA here is not standard and can be unreliable. Docker Compose attempts to substitute this variable from the host machine's environment, where it is likely undefined. To ensure the database data is persisted correctly, you should use the absolute path where the PostgreSQL image stores its data by default. The correct path is /var/lib/postgresql/data.


volumes:
my_db:
my_media:
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ djangorestframework
djangorestframework-simplejwt
drf-spectacular
Pillow
psycopg==3.1.12
psycopg-binary==3.1.12
Loading