Compare commits

...

71 Commits

Author SHA1 Message Date
e0675c8684 Merge pull request 'Update .env.template' (#18) from woutervermeer-patch-1 into main
Some checks failed
Gitea build & Test. / tests (push) Failing after 5s
Deploy to production / deploy (push) Failing after 31s
Gitea build & Test. / tests (pull_request) Failing after 6s
Gitea Test. / tests (pull_request) Successful in 6s
Reviewed-on: #18
2026-03-26 09:52:42 +00:00
4b18769137 Update .env.template
Some checks failed
Gitea build & Test. / tests (pull_request) Failing after 7s
Gitea Test. / tests (pull_request) Successful in 6s
2026-03-26 09:52:33 +00:00
90b7bb0dee Merge pull request 'pre-prod' (#17) from pre-prod into main
Some checks failed
Gitea build & Test. / tests (push) Failing after 6s
Deploy to production / deploy (push) Failing after 1m19s
Reviewed-on: #17
2026-03-26 08:17:36 +00:00
8cfe5c6f9b Add .gitea/workflows/test.yaml
Some checks failed
Gitea Test. / tests (push) Successful in 6s
Gitea build & Test. / tests (pull_request) Failing after 6s
Gitea Test. / tests (pull_request) Successful in 6s
2026-03-26 08:15:11 +00:00
9397c2d4f2 Update .gitea/workflows/build_test.yaml
Some checks failed
Gitea build & Test. / tests (pull_request) Failing after 6s
2026-03-26 08:14:25 +00:00
313702f9fe Update Makefile
Some checks failed
Gitea build & Test. / tests (push) Failing after 13s
Gitea build & Test. / tests (pull_request) Failing after 7s
2026-03-26 08:09:28 +00:00
WGAVermeer
49199b7184 slightly updated README.md
Some checks failed
Gitea build & Test. / tests (push) Failing after 7s
2026-03-26 08:27:10 +01:00
WGAVermeer
c17e3e85f2 added auto-reload when developing.
Some checks failed
Gitea build & Test. / tests (push) Failing after 21s
2026-03-25 17:11:14 +01:00
WGAVermeer
be54afa093 fix makefile pt2
Some checks failed
Gitea build & Test. / tests (push) Failing after 27s
2026-03-25 15:47:29 +01:00
WGAVermeer
fd5414bd5a fix type in makefile
Some checks failed
Gitea build & Test. / tests (push) Failing after 2s
2026-03-25 15:46:46 +01:00
WGAVermeer
6b635955eb Merge branch 'pre-prod' of https://gitea.woutervermeer.com/woutervermeer/Quatsh-Website into pre-prod
Some checks failed
Gitea build & Test. / tests (push) Failing after 3s
2026-03-25 15:44:27 +01:00
WGAVermeer
0610053a3e added nginx as a proxy. Still need to enable ssl. 2026-03-25 15:44:17 +01:00
79560c5835 Merge pull request 'woutervermeer-patch-1' (#16) from woutervermeer-patch-1 into pre-prod
Some checks failed
Gitea build & Test. / tests (push) Failing after 6s
Reviewed-on: woutervermeer/Quatsh-Website#16
2026-03-11 08:49:35 +00:00
c1aa69dd8b Update .gitea/workflows/build_test.yaml
Some checks failed
Gitea build & Test. / tests (pull_request) Failing after 6s
2026-03-11 08:49:20 +00:00
d17b2f0a2a Merge pull request 'Change workflow stuff, update Readme, update .env handling' (#15) from pre-prod into main
Some checks failed
Gitea build & Test. / tests (push) Successful in 5s
Deploy to production / deploy (push) Failing after 26s
Reviewed-on: woutervermeer/Quatsh-Website#15
2026-03-11 08:39:52 +00:00
41a61fb318 Update .gitea/workflows/build_test.yaml
All checks were successful
Gitea build & Test. / tests (push) Successful in 6s
Gitea build & Test. / tests (pull_request) Successful in 5s
2026-03-11 08:38:41 +00:00
cba945375c Update .gitea/workflows/deploy.yml
All checks were successful
Gitea build & Test. / tests (push) Successful in 6s
2026-03-11 08:38:29 +00:00
WGAVermeer
1c545638b9 run deploy check aswell. 2026-03-11 09:26:45 +01:00
WGAVermeer
5fa195a0dc Merge branch 'pre-prod' of https://gitea.woutervermeer.com/woutervermeer/Quatsh-Website into pre-prod
All checks were successful
Gitea build & Test. / tests (push) Successful in 18s
2026-03-11 09:24:52 +01:00
WGAVermeer
f8dc8fc684 remove hardcoded .env 2026-03-11 09:24:45 +01:00
df587931b5 Merge pull request 'woutervermeer-patch-1' (#14) from woutervermeer-patch-1 into pre-prod
Some checks failed
Gitea build & Test. / tests (push) Failing after 3s
Reviewed-on: woutervermeer/Quatsh-Website#14
2026-03-11 08:23:40 +00:00
WGAVermeer
01ea42b64a default to non-debug mode.
Some checks failed
Gitea build & Test. / tests (push) Failing after 3s
2026-03-11 09:22:58 +01:00
WGAVermeer
fe6c0df123 Updated settings to import secret key.
Some checks failed
Gitea build & Test. / tests (push) Failing after 3s
2026-03-11 09:21:36 +01:00
357c81ff08 Update README.md
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 6s
2026-03-11 07:30:02 +00:00
WGAVermeer
26c6f46531 added poll app for testing purposes. Will be removed later.
Some checks failed
Gitea build & Test. / tests (push) Failing after 3s
2026-03-11 08:13:35 +01:00
WGAVermeer
13a317d3df Make Dev enters into the webserver shell.
Fixed database env variables to properly connect.
2026-03-11 08:12:07 +01:00
026bce1f16 Merge pull request 'Update README.md' (#13) from woutervermeer-patch-1 into main
All checks were successful
Deploy to production / deploy (push) Successful in 18s
Reviewed-on: woutervermeer/Quatsh-Website#13
2026-03-09 12:41:08 +00:00
b1f44f2ce0 Update README.md
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 6s
2026-03-09 12:40:37 +00:00
761227e05e Merge pull request 'pre-prod' (#12) from pre-prod into main
All checks were successful
Deploy to production / deploy (push) Successful in 19s
Reviewed-on: woutervermeer/Quatsh-Website#12
2026-03-08 14:34:16 +00:00
c165c03579 Merge pull request 'woutervermeer-patch-5' (#11) from woutervermeer-patch-5 into pre-prod
All checks were successful
Gitea build & Test. / tests (push) Successful in 6s
Gitea build & Test. / tests (pull_request) Successful in 5s
Reviewed-on: woutervermeer/Quatsh-Website#11
2026-03-08 14:31:30 +00:00
badf0dde7a Update Makefile
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 5s
2026-03-08 14:31:15 +00:00
b1f25ebcc3 Merge pull request 'Update .gitea/workflows/deploy.yml' (#10) from woutervermeer-patch-5 into main
Some checks failed
Deploy to production / deploy (push) Has been cancelled
Reviewed-on: woutervermeer/Quatsh-Website#10
2026-03-08 14:30:03 +00:00
01c8640d38 Update .gitea/workflows/deploy.yml
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 7s
2026-03-08 14:29:55 +00:00
f511599273 Merge pull request 'Update .gitea/workflows/deploy.yml' (#9) from woutervermeer-patch-4 into main
All checks were successful
Deploy to production / deploy (push) Successful in 4s
Reviewed-on: woutervermeer/Quatsh-Website#9
2026-03-08 14:23:11 +00:00
bac4c56485 Update .gitea/workflows/deploy.yml
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 6s
2026-03-08 14:23:03 +00:00
e1a6e4f21f Merge pull request 'Update .gitea/workflows/build_test.yaml' (#8) from woutervermeer-patch-3 into main
Some checks failed
Deploy to production / deploy (push) Has been cancelled
Reviewed-on: woutervermeer/Quatsh-Website#8
2026-03-08 14:22:40 +00:00
2f1102bebc Update .gitea/workflows/build_test.yaml
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 6s
2026-03-08 14:22:31 +00:00
f24bf52136 Merge pull request 'Update .gitea/workflows/deploy.yml' (#7) from woutervermeer-patch-1 into main
Some checks failed
Gitea build & Test. / tests (push) Successful in 6s
Deploy to production / deploy (push) Has been cancelled
Reviewed-on: woutervermeer/Quatsh-Website#7
2026-03-08 14:19:53 +00:00
0f98959d37 Update .gitea/workflows/deploy.yml
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 6s
2026-03-08 14:19:44 +00:00
e99f44d8ad Merge pull request 'pre-prod' (#6) from pre-prod into main
All checks were successful
Gitea build & Test. / tests (push) Successful in 6s
Reviewed-on: woutervermeer/Quatsh-Website#6
2026-03-08 14:18:31 +00:00
5b9d70db22 Update .gitea/workflows/deploy.yml
All checks were successful
Gitea build & Test. / tests (push) Successful in 6s
Gitea build & Test. / tests (pull_request) Successful in 5s
2026-03-08 14:17:19 +00:00
ac4e92aa07 Merge pull request 'Update .gitea/workflows/build_test.yaml' (#4) from woutervermeer-patch-2 into pre-prod
All checks were successful
Gitea build & Test. / tests (push) Successful in 6s
Gitea build & Test. / tests (pull_request) Successful in 5s
Reviewed-on: woutervermeer/Quatsh-Website#4
2026-03-08 14:15:24 +00:00
b94c208798 Merge pull request 'woutervermeer-patch-3' (#3) from woutervermeer-patch-3 into pre-prod
All checks were successful
Gitea build & Test. / docker (push) Successful in 6s
Reviewed-on: woutervermeer/Quatsh-Website#3
2026-03-08 14:14:50 +00:00
f293a34923 Add .gitea/workflows/deploy.yml
All checks were successful
Gitea build & Test. / docker (pull_request) Successful in 7s
2026-03-08 14:14:34 +00:00
56c54c973f Update .gitea/workflows/build_test.yaml
All checks were successful
Gitea build & Test. / tests (pull_request) Successful in 6s
2026-03-08 14:13:48 +00:00
3984dfb058 Merge pull request 'Update .gitea/workflows/build_test.yaml' (#2) from woutervermeer-patch-1 into main
All checks were successful
Gitea build & Test. / docker (push) Successful in 5s
Reviewed-on: woutervermeer/Quatsh-Website#2
2026-03-08 14:08:07 +00:00
bcb72b42e1 Update .gitea/workflows/build_test.yaml
All checks were successful
Gitea build & Test. / docker (pull_request) Successful in 7s
2026-03-08 14:07:52 +00:00
86c3cfe426 revert 7ecd65b9c2
All checks were successful
Gitea build & Test. / docker (push) Successful in 6s
revert cleanup
2026-03-08 13:56:48 +00:00
WGAVermeer
7ecd65b9c2 cleanup
Some checks failed
Gitea build & Test. / docker (push) Failing after 5s
2026-03-08 14:54:29 +01:00
WGAVermeer
8e4e2b8434 pray
All checks were successful
Gitea build & Test. / docker (push) Successful in 6s
2026-03-08 14:53:24 +01:00
WGAVermeer
dda1b29626 fix typo in compose.test.yaml
Some checks failed
Gitea build & Test. / docker (push) Failing after 6s
2026-03-08 14:41:27 +01:00
WGAVermeer
d999fece6f specified db info
Some checks failed
Gitea build & Test. / docker (push) Failing after 3s
2026-03-08 14:39:31 +01:00
WGAVermeer
cbf5e4b503 choose correct .env
Some checks failed
Gitea build & Test. / docker (push) Failing after 19s
2026-03-08 14:36:06 +01:00
WGAVermeer
9959272051 test version runs
Some checks failed
Gitea build & Test. / docker (push) Failing after 3s
2026-03-08 14:20:43 +01:00
WGAVermeer
3fca18e000 remove quotes from compose.test.yaml
Some checks failed
Gitea build & Test. / docker (push) Failing after 3s
2026-03-08 14:02:39 +01:00
WGAVermeer
0f57d9f32b change gitignore to push template
Some checks failed
Gitea build & Test. / docker (push) Failing after 3s
2026-03-08 13:58:34 +01:00
WGAVermeer
518364faa9 Merge branch 'main' of https://gitea.woutervermeer.com/woutervermeer/Quatsh-Website 2026-03-08 13:57:30 +01:00
WGAVermeer
b680c1ab5f fix .env.template
:
2026-03-08 13:57:24 +01:00
27257a2977 Update .gitea/workflows/build.yaml
Some checks failed
Gitea build & Test. / docker (push) Failing after 3s
2026-03-08 12:55:34 +00:00
WGAVermeer
8049cb2e62 Merge branch 'main' of https://gitea.woutervermeer.com/woutervermeer/Quatsh-Website
Some checks failed
Gitea build & run. / docker (push) Failing after 3s
2026-03-08 13:54:48 +01:00
WGAVermeer
600baaee80 attempting creation of testing mode. 2026-03-08 13:54:16 +01:00
14f2665070 Update .gitea/workflows/build.yaml
Some checks failed
Gitea build & run. / docker (push) Failing after 4s
2026-03-08 12:24:59 +00:00
WGAVermeer
acc116a6c1 added dev make file for ease in development.
Some checks failed
Gitea build & run. / docker (push) Failing after 3s
2026-03-08 13:20:45 +01:00
vps - Wouter
c9eb6d52be fix issue, dockerfile was using a cached image
Some checks failed
Gitea build & run. / docker (push) Failing after 3s
2026-03-08 11:47:41 +00:00
WGAVermeer
6511120965 updated .env insertion for db to use new .env variables
Some checks failed
Gitea build & run. / docker (push) Failing after 3s
2026-03-06 19:14:36 +01:00
b25196545f Merge pull request 'init_development' (#1) from init_development into main
Some checks failed
Gitea build & run. / docker (push) Failing after 3s
Reviewed-on: woutervermeer/Quatsh-Website#1
2026-03-06 18:11:55 +00:00
WGAVermeer
9e8d43e210 updated .env insertation
Some checks failed
Gitea build & run. / docker (pull_request) Failing after 10s
2026-03-06 18:25:33 +01:00
WGAVermeer
5160a06aa2 updated .env insertation 2026-03-06 18:16:21 +01:00
WGAVermeer
9b57180e20 updated workflow 2026-03-06 16:59:38 +01:00
WGAVermeer
d359cb9780 working database connection in Django 2026-03-06 16:56:14 +01:00
WGAVermeer
860b0ef033 renamed to src 2026-03-06 15:12:32 +01:00
35 changed files with 636 additions and 137 deletions

View File

@@ -0,0 +1,14 @@
services:
web:
command: python manage.py check --deploy
restart: "no"
env_file:
- path: .env.template
required: true
db:
env_file:
- path: .env.template
required: true

View File

@@ -0,0 +1,18 @@
services:
web:
command: gunicorn --capture-output --enable-stdio-inheritance -b 0.0.0.0:8000 website.wsgi:application
volumes:
- ./src:/src
env_file:
- path: .env.template
required: true
- path: .env
required: false
db:
env_file:
- path: .env.template
required: true
- path: .env
required: false

View File

@@ -0,0 +1,10 @@
services:
web:
env_file:
- path: .env
required: true
db:
env_file:
- path: .env
required: true

View 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

20
.env.template Normal file
View File

@@ -0,0 +1,20 @@
#NGINX
NGINX_HOSTNAME=localhost
# Django
DJANGO_SETTINGS_MODULE=website.settings
DJANGO_SECRET_KEY=CWHZCAZBNV57tDkwGHJwTUu3PCSnGG45
DEBUG=TRUE
#ALLOWED_HOSTS=localhost
# Database (PostgreSQL)
POSTGRES_USER=test_user
POSTGRES_PASSWORD=test_password
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_DBNAME=test_dbname # == POSTGRES_DB
POSTGRES_DB=test_db
# Gunicorn
GUNICORN_WORKERS=3
GUNICORN_TIMEOUT=120

View File

@@ -0,0 +1,20 @@
name: Gitea build & Test.
run-name: ${{ gitea.actor }}
on:
push:
branches:
- main
pull_request:
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build and test
run: make test
- name: Build
run: make prod

View File

@@ -0,0 +1,38 @@
name: Deploy to production
run-name: deploy-${{ gitea.actor }}
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts
- name: Deploy
run: |
ssh -i ~/.ssh/id_rsa ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} << 'EOF'
cd ~/Quatsh-Website
echo "Pulling latest code..."
git pull origin main
echo "Building containers..."
make prod
echo "Running Django deploy check"
docker compose run --rm web python manage.py check --deploy
echo "Deployment complete."
EOF

View File

@@ -0,0 +1,17 @@
name: Gitea Test.
run-name: ${{ gitea.actor }}
on:
push:
branches:
- pre-prod
pull_request:
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: test
run: make test

5
.gitignore vendored
View File

@@ -136,6 +136,7 @@ venv/
ENV/
env.bak/
venv.bak/
!.env.template
# Spyder project settings
.spyderproject
@@ -174,3 +175,7 @@ cython_debug/
# PyPI configuration file
.pypirc
# gunicon webserver
gunicorn.ctl

3
.nginx/.conf Normal file
View File

@@ -0,0 +1,3 @@
events {}
http {}

View 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;
}
}

View File

@@ -1,16 +1,13 @@
FROM python:3.14-alpine
RUN mkdir /app
WORKDIR /src
WORKDIR /app
COPY requirements.txt /src/
COPY gunicorn.conf.py /src/
COPY ./src/ /src/
RUN pip install --upgrade pip
COPY requirements.txt /app/
COPY gunicorn.conf.py /app/
COPY ./app/ /app/
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
EXPOSE 8000

26
Makefile Normal file
View File

@@ -0,0 +1,26 @@
prod:
docker compose down
docker compose --env-file .env -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:
docker compose down
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
dev_restart:
docker compose down
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.dev.yaml up -d
docker exec -it quatsh-website-web-1 sh
dev_restart_with_logs:
docker compose down
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.dev.yaml up
test:
docker compose --env-file .env.template -f ./compose.yaml -f ./.docker-compose-files/compose.test.yaml up --build --abort-on-container-exit --exit-code-from web

View File

@@ -1,2 +1,65 @@
# Quatsh-Website
## Requirements
### Install make
Running this requires the use of "make" and docker.
"make" tends to come pre-installed on linux but not on Windows, to install it on Windows I recommend using Chocolatey as follows: \
```
choco install make
```
### Install docker
<https://docs.docker.com/get-started/get-docker/>
## Running for the first time
### Env
Before running the container environment has to be setup first, so first run:
```
cp .env.template .env
```
Then make any changes to the .env file.
### Running the website
To run the website 3 options have been provided
#### Development
For development purposes only as the src folder has been mounted in the container to allow for the making of changes without rebuilding the entire image.
Properly utilising this also requires the DEBUG environment variable to be set to TRUE.
```shell
make dev
```
#### Testing
Runs the testing environment and exits.
```shell
make test
```
#### Production
Using `make prod` is identical but preferred here.
```shell
make prod
```
Or
```shell
make
```

View File

@@ -1,117 +0,0 @@
"""
Django settings for website project.
Generated by 'django-admin startproject' using Django 6.0.3.
For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-c$q7wdq+u@ow74wp!&zzkxdylkueu)(+34e%!e0du&bjwoqz9z'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'website.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'website.wsgi.application'
# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/6.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/
STATIC_URL = 'static/'

View File

@@ -1,9 +1,67 @@
services:
web:
build: .
ports:
- 8000:8000
command: gunicorn website.wsgi:application
depends_on:
- db
environment:
- PYTHONDONTWRITEBYTECODE=1
- PYTHONUNBUFFERED=1
ALLOWED_HOSTS: ${NGINX_HOSTNAME}
PYTHONDONTWRITEBYTECODE: 1
PYTHONUNBUFFERED: 1
DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE}
VIRTUAL_HOST: localhost
#VIRTUAL_PORT: 8000
restart: unless-stopped
volumes:
- static_volume:/app/static
- media_volume:/app/media
db:
image: postgres:18
environment:
POSTGRES_DB: ${POSTGRES_DBNAME}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql
restart: unless-stopped
adminer:
image: adminer
depends_on:
- db
restart: always
ports:
- 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:
build: .
command: python manage.py test
depends_on:
- db
profiles:
- test
volumes:
postgres_data:
static_volume:
media_volume:

View File

@@ -1,5 +0,0 @@
services:
web:
volumes:
- ./app:/app

View File

@@ -1,2 +1,5 @@
Django==6.0.3
gunicorn==25.1.0
psycopg [binary] ==3.3.3
django-browser-reload
django-watchfiles

7
src/polls/admin.py Normal file
View File

@@ -0,0 +1,7 @@
from django.contrib import admin
# Register your models here.
from .models import Question
admin.site.register(Question)

5
src/polls/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'

View 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')),
],
),
]

View File

20
src/polls/models.py Normal file
View File

@@ -0,0 +1,20 @@
from django.db import models
# 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

View File

@@ -0,0 +1,11 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>My test page</title>
</head>
<body>
<h1>Hey This is a test of watchfiles + browser reload!</h1>
{{ question }}
</body>
</html>

View File

@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>My test page</title>
</head>
<body>
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
</body>
</html>

3
src/polls/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

14
src/polls/urls.py Normal file
View File

@@ -0,0 +1,14 @@
from django.urls import path
from . import views
urlpatterns = [
# ex: /polls/
path("", views.index, name="index"),
# ex: /polls/5/
path("<int:question_id>/", views.detail, name="detail"),
# ex: /polls/5/results/
path("<int:question_id>/results/", views.results, name="results"),
# ex: /polls/5/vote/
path("<int:question_id>/vote/", views.vote, name="vote"),
]

24
src/polls/views.py Normal file
View File

@@ -0,0 +1,24 @@
from django.http import HttpResponse, Http404
from django.shortcuts import get_object_or_404, render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by("-pub_date")[:5]
context = {"latest_question_list": latest_question_list}
return render(request, "polls/index.html", context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)

0
src/website/__init__.py Normal file
View File

128
src/website/settings.py Normal file
View File

@@ -0,0 +1,128 @@
"""
Django settings for website project.
Generated by 'django-admin startproject' using Django 6.0.3.
For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv("DEBUG") == "TRUE"
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "127.0.0.1").split(",")
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
# Application definition
INSTALLED_APPS = [
"polls.apps.PollsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django_browser_reload",
"django_watchfiles",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django_browser_reload.middleware.BrowserReloadMiddleware",
]
ROOT_URLCONF = "website.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "website.wsgi.application"
# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv("POSTGRES_DBNAME"),
"USER": os.getenv("POSTGRES_USER"),
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
"HOST": os.getenv("POSTGRES_HOST"),
"PORT": os.getenv("POSTGRES_PORT"),
}
}
# Password validation
# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/6.0/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "Europe/Amsterdam"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/
STATIC_ROOT = "/app/static/"
STATIC_URL = "static/"

View File

@@ -14,9 +14,12 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path("__reload__/", include("django_browser_reload.urls")),
path("polls/", include("polls.urls")),
path("admin/", admin.site.urls),
]