Skip to content

Commit 1db550e

Browse files
committed
adding docker
1 parent e3c7a39 commit 1db550e

File tree

12 files changed

+134
-86
lines changed

12 files changed

+134
-86
lines changed

.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ src/django_project/*.sqlite3
99
src/django_project/*.log
1010
src/django_project/local_test
1111
src/django_project/tests
12+
13+
src/django_project/core/static/node_modules
14+
src/django_project/core/static/package.json
15+
src/django_project/core/static/package-lock.json

pyproject.toml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22
dependencies = [
33
"django~=5.2",
44
"django-braces",
5+
"django-debug-toolbar",
56
"django-environ",
67
"django-extensions",
78
"django-filter",
8-
"django-handyhelpers",
9+
"django-handyhelpers==0.3.41",
910
"djangorestframework",
1011
"djangorestframework-filters==1.0.0.dev0",
1112
"drf-flex-fields",
1213
"drf-spectacular",
1314
"drf-renderer-xlsx",
14-
"psycopg2-binary",
15-
"whitenoise",
1615
]
1716
description = "Spokane Python Community"
1817
dynamic = ["version"]
@@ -27,7 +26,6 @@ requires-python = ">=3.10"
2726
dev = [
2827
"bandit",
2928
"coveralls",
30-
"django-debug-toolbar",
3129
"faker",
3230
"isort",
3331
"model-bakery",
@@ -43,6 +41,11 @@ dev = [
4341
"types-requests",
4442
"typing_extensions",
4543
]
44+
docker = [
45+
"gunicorn",
46+
"psycopg2-binary",
47+
"whitenoise",
48+
]
4649

4750

4851
[tool.bandit]

src/django_project/core/settings.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838

3939
# SECURITY WARNING: don't run with debug turned on in production!
4040
DEBUG = env.bool("DEBUG", True)
41+
DEPLOYMENT_ENV = env.str("DEPLOYMENT_ENV", "local")
42+
4143

4244
ALLOWED_HOSTS = env.str("ALLOWED_HOSTS", "127.0.0.1").split(",")
4345
INTERNAL_IPS = env.str("INTERNAL_IPS", "127.0.0.1").split(",")
@@ -52,7 +54,6 @@
5254
"django.contrib.messages",
5355
"django.contrib.staticfiles",
5456
# third party apps
55-
"debug_toolbar",
5657
"django_extensions",
5758
"django_filters",
5859
"drf_spectacular",
@@ -66,14 +67,22 @@
6667

6768
MIDDLEWARE = [
6869
"django.middleware.security.SecurityMiddleware",
70+
"whitenoise.middleware.WhiteNoiseMiddleware",
6971
"django.contrib.sessions.middleware.SessionMiddleware",
7072
"django.middleware.common.CommonMiddleware",
7173
"django.middleware.csrf.CsrfViewMiddleware",
7274
"django.contrib.auth.middleware.AuthenticationMiddleware",
7375
"django.contrib.messages.middleware.MessageMiddleware",
7476
"django.middleware.clickjacking.XFrameOptionsMiddleware",
75-
"debug_toolbar.middleware.DebugToolbarMiddleware",
7677
]
78+
if DEPLOYMENT_ENV in ["local", "dev"]:
79+
INSTALLED_APPS += [
80+
"debug_toolbar", # pragma: no cover
81+
]
82+
MIDDLEWARE += [
83+
"debug_toolbar.middleware.DebugToolbarMiddleware", # pragma: no cover
84+
]
85+
7786

7887
ROOT_URLCONF = "core.urls"
7988

src/django_project/core/static/package-lock.json

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/django_project/core/urls/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
path("", include("web.urls", namespace="web")),
4242
]
4343

44-
if settings.DEBUG:
44+
if settings.DEBUG and settings.DEPLOYMENT_ENV in ["local", "dev"]:
4545
urlpatterns.append(
4646
path("__debug__/", include("debug_toolbar.urls")),
4747
) # pragma: no cover

src/django_project/entrypoint.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/sh
2+
3+
# Exit immediately if a command exits with a non-zero status
4+
set -e
5+
6+
# Function to wait for the database to be ready
7+
wait_for_db() {
8+
echo "Waiting for database to be ready..."
9+
until nc -z "$DB_HOST" "$DB_PORT"; do
10+
echo "Database is unavailable - sleeping"
11+
sleep 1
12+
done
13+
echo "Database is up - continuing"
14+
}
15+
16+
# Wait for the database to be ready
17+
wait_for_db
18+
19+
# Run migrations
20+
echo "Running migrations..."
21+
python manage.py migrate
22+
23+
# Create superuser
24+
echo "Creating superuser..."
25+
python manage.py add_superuser --username $DJANGO_ADMIN_USERNAME --group admin --password $DJANGO_ADMIN_PASSWORD
26+
27+
# Collect static files
28+
echo "Collecting static files..."
29+
python manage.py collectstatic --noinput
30+
31+
# Launch gunicorn
32+
gunicorn core.wsgi:application --bind 0.0.0.0:8000 --workers 3

src/django_project/web/migrations/0001_initial.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 5.2.4 on 2025-07-27 20:48
1+
# Generated by Django 5.2.4 on 2025-07-29 22:16
22

33
import django.db.models.deletion
44
from django.db import migrations, models
@@ -21,6 +21,7 @@ class Migration(migrations.Migration):
2121
("end_date_time", models.DateTimeField()),
2222
("location", models.CharField(blank=True, max_length=256, null=True)),
2323
("description", models.TextField(blank=True, null=True)),
24+
("url", models.URLField(blank=True, null=True)),
2425
],
2526
options={
2627
"ordering": ["-start_date_time"],
@@ -37,7 +38,7 @@ class Migration(migrations.Migration):
3738
("title", models.CharField(max_length=128)),
3839
("description", models.TextField()),
3940
(
40-
"target_audience",
41+
"skill_level",
4142
models.CharField(
4243
choices=[
4344
("all", "All Levels"),

src/django_project/web/migrations/0002_event_url.py

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/django_project/web/migrations/0003_rename_target_audience_presentationrequest_skill_level.py

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/docker/Dockerfile

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# === STAGE 1: Build dependencies in a virtual environment ===
2+
FROM python:3.12-alpine AS builder
3+
4+
WORKDIR /app
5+
6+
# Install build dependencies
7+
RUN apk add --no-cache \
8+
gcc \
9+
musl-dev \
10+
libffi-dev \
11+
openssl-dev
12+
13+
COPY pyproject.toml /app/
14+
15+
# Install pip-tools and create a virtual environment
16+
RUN pip install --upgrade pip
17+
RUN python -m venv /venv
18+
ENV PATH="/venv/bin:$PATH"
19+
RUN pip install .[docker]
20+
21+
22+
# === STAGE 2: Runtime with only necessary files ===
23+
FROM python:3.12-alpine
24+
25+
ENV PYTHONDONTWRITEBYTECODE=1
26+
ENV PYTHONUNBUFFERED=1
27+
28+
WORKDIR /app
29+
30+
# Install minimal runtime dependencies
31+
RUN apk add --no-cache libffi openssl libstdc++
32+
33+
# Copy the virtual environment from the builder stage
34+
COPY --from=builder /venv /venv
35+
36+
# Add the virtual environment's Python to the PATH
37+
ENV PATH="/venv/bin:$PATH"
38+
39+
# Copy Django project code
40+
COPY src/django_project /app/
41+
RUN chmod +x /app/entrypoint.sh
42+
43+
EXPOSE 8000
44+
45+
CMD ["gunicorn", "core.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]

0 commit comments

Comments
 (0)