Compare commits
3 Commits
79560c5835
...
6b635955eb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b635955eb | ||
|
|
0610053a3e | ||
|
|
1c545638b9 |
@@ -1,11 +1,12 @@
|
|||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
command: python -Wa manage.py test --noinput --parallel
|
command: python manage.py check --deploy
|
||||||
restart: "no"
|
restart: "no"
|
||||||
env_file:
|
env_file:
|
||||||
- path: .env.template
|
- path: .env.template
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
env_file:
|
env_file:
|
||||||
- path: .env.template
|
- path: .env.template
|
||||||
14
.docker-compose-files/compose.test.yaml
Normal file
14
.docker-compose-files/compose.test.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
web:
|
||||||
|
command: python manage.py check --deploy; python -Wa manage.py test --noinput --parallel
|
||||||
|
restart: "no"
|
||||||
|
env_file:
|
||||||
|
- path: .env.template
|
||||||
|
required: true
|
||||||
|
|
||||||
|
|
||||||
|
db:
|
||||||
|
env_file:
|
||||||
|
- path: .env.template
|
||||||
|
required: true
|
||||||
|
|
||||||
3
.nginx/.conf
Normal file
3
.nginx/.conf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
events {}
|
||||||
|
|
||||||
|
http {}
|
||||||
49
.nginx/.templates/nginx.conf.template
Normal file
49
.nginx/.templates/nginx.conf.template
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
server {
|
||||||
|
listen ${NGINX_PORT};
|
||||||
|
server_name ${NGINX_HOSTNAME};
|
||||||
|
|
||||||
|
location /static/ {
|
||||||
|
alias /app/static/;
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public";
|
||||||
|
}
|
||||||
|
|
||||||
|
location /media/ {
|
||||||
|
alias /app/media;
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public";
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://web:8000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen ${NGINX_SSL_PORT};
|
||||||
|
server_name ${NGINX_HOSTNAME};
|
||||||
|
|
||||||
|
location /static/ {
|
||||||
|
alias /app/static/;
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public";
|
||||||
|
}
|
||||||
|
|
||||||
|
location /media/ {
|
||||||
|
alias /app/media;
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public";
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://web:8000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Makefile
11
Makefile
@@ -1,11 +1,16 @@
|
|||||||
prod:
|
prod:
|
||||||
docker compose down
|
docker compose down
|
||||||
docker compose -f ./compose.yaml -f ./compose.prod.yaml up -d --build
|
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.prod.yaml up -d --build
|
||||||
|
docker exec quatsh-website-web-1 python manage.py collectstatic --noinput
|
||||||
|
docker exec quatsh-website-web-1 python manage.py check --deploy
|
||||||
|
docker exec quatsh-website-web-1 python manage.py migrate
|
||||||
|
|
||||||
dev:
|
dev:
|
||||||
docker compose down
|
docker compose down
|
||||||
docker compose -f ./compose.yaml -f ./compose.dev.yaml up --build -d
|
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.dev.yaml up --build -d
|
||||||
|
docker exec quatsh-website-web-1 python manage.py collectstatic --noinput
|
||||||
docker exec -it quatsh-website-web-1 sh
|
docker exec -it quatsh-website-web-1 sh
|
||||||
|
|
||||||
test:
|
test:
|
||||||
docker compose --env-file .env.template -f ./compose.yaml -f ./compose.test.yaml up --build --abort-on-container-exit --exit-code-from web
|
docker compose --env-file .env.template -f ./compose.yaml -f ./.docker-compose_files up --build --abort-on-container-exit --exit-code-from web
|
||||||
|
|
||||||
|
|||||||
30
compose.yaml
30
compose.yaml
@@ -1,16 +1,21 @@
|
|||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
command: gunicorn --proxy-protocol auto --proxy-allow-from 10.10.50.11 website.wsgi:application
|
command: gunicorn website.wsgi:application
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
ports:
|
|
||||||
- 8000:8000
|
|
||||||
environment:
|
environment:
|
||||||
|
ALLOWED_HOSTS: ${NGINX_HOSTNAME}
|
||||||
PYTHONDONTWRITEBYTECODE: 1
|
PYTHONDONTWRITEBYTECODE: 1
|
||||||
PYTHONUNBUFFERED: 1
|
PYTHONUNBUFFERED: 1
|
||||||
DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE}
|
DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE}
|
||||||
|
VIRTUAL_HOST: localhost
|
||||||
|
#VIRTUAL_PORT: 8000
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- static_volume:/app/static
|
||||||
|
- media_volume:/app/media
|
||||||
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:18
|
image: postgres:18
|
||||||
@@ -30,6 +35,23 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
|
|
||||||
|
proxy:
|
||||||
|
image: nginx:stable
|
||||||
|
volumes:
|
||||||
|
- ./.nginx/.templates:/etc/nginx/templates
|
||||||
|
- static_volume:/app/static:ro
|
||||||
|
- media_volume:/app/media:ro
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
- 443:443
|
||||||
|
environment:
|
||||||
|
- NGINX_HOSTNAME=${NGINX_HOSTNAME}
|
||||||
|
- NGINX_PORT=80
|
||||||
|
- NGINX_SSL_PORT=443
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
|
||||||
test:
|
test:
|
||||||
build: .
|
build: .
|
||||||
command: python manage.py test
|
command: python manage.py test
|
||||||
@@ -41,3 +63,5 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
static_volume:
|
||||||
|
media_volume:
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
|
|
||||||
|
from .models import Question
|
||||||
|
|
||||||
|
admin.site.register(Question)
|
||||||
|
|||||||
32
src/polls/migrations/0001_initial.py
Normal file
32
src/polls/migrations/0001_initial.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Generated by Django 6.0.3 on 2026-03-25 14:26
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Question',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('question_text', models.CharField(max_length=200)),
|
||||||
|
('pub_date', models.DateTimeField(verbose_name='date published')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Choice',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('choice_text', models.CharField(max_length=200)),
|
||||||
|
('votes', models.IntegerField(default=0)),
|
||||||
|
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.question')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,3 +1,20 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
|
||||||
|
class Question(models.Model):
|
||||||
|
question_text = models.CharField(max_length=200)
|
||||||
|
pub_date = models.DateTimeField("date published")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.question_text
|
||||||
|
|
||||||
|
|
||||||
|
class Choice(models.Model):
|
||||||
|
question = models.ForeignKey(Question, on_delete=models.CASCADE)
|
||||||
|
choice_text = models.CharField(max_length=200)
|
||||||
|
votes = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.choice_text
|
||||||
|
|||||||
@@ -24,15 +24,16 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
|
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = bool(os.getenv("DEBUG", False))
|
DEBUG = os.getenv("DEBUG") == "TRUE"
|
||||||
|
|
||||||
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS").split(",")
|
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "127.0.0.1").split(",")
|
||||||
|
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
"polls.apps.PollsConfig",
|
||||||
"django.contrib.admin",
|
"django.contrib.admin",
|
||||||
"django.contrib.auth",
|
"django.contrib.auth",
|
||||||
"django.contrib.contenttypes",
|
"django.contrib.contenttypes",
|
||||||
@@ -120,4 +121,5 @@ USE_TZ = True
|
|||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/6.0/howto/static-files/
|
# https://docs.djangoproject.com/en/6.0/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_ROOT = "/app/static/"
|
||||||
STATIC_URL = "static/"
|
STATIC_URL = "static/"
|
||||||
|
|||||||
Reference in New Issue
Block a user