add superuser creation command and update settings for environment variables

This commit is contained in:
2025-05-26 23:40:57 +02:00
parent dbe83c9616
commit 4e79d7c1de
11 changed files with 168 additions and 6 deletions

9
.env.example Normal file
View File

@@ -0,0 +1,9 @@
# Django settings
DJANGO_SUPERUSER_USERNAME=admin
DJANGO_SUPERUSER_EMAIL=admin@example.com
DJANGO_SUPERUSER_PASSWORD=adminpassword
DEBUG=False
SECRET_KEY=your-secret-key
ALLOWED_HOSTS=localhost,127.0.0.1
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000

2
.gitignore vendored
View File

@@ -33,3 +33,5 @@ build/
*.log
*.tmp
*.swp
.env

18
Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt /app/
# Install dependencies
RUN pip install --upgrade pip \
&& pip install -r requirements.txt \
&& pip install gunicorn
# Copy the rest of the project
COPY . /app/
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

View File

View File

View File

@@ -0,0 +1,18 @@
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
import os
class Command(BaseCommand):
help = "Create a superuser if it doesn't already exist"
def handle(self, *args, **kwargs):
User = get_user_model()
username = os.getenv("DJANGO_SUPERUSER_USERNAME")
email = os.getenv("DJANGO_SUPERUSER_EMAIL")
password = os.getenv("DJANGO_SUPERUSER_PASSWORD")
if not User.objects.filter(username=username).exists():
User.objects.create_superuser(username=username, email=email, password=password)
self.stdout.write(self.style.SUCCESS(f"Superuser {username} created"))
else:
self.stdout.write(self.style.WARNING(f"Superuser {username} already exists"))

19
docker-compose.yml Normal file
View File

@@ -0,0 +1,19 @@
services:
web:
build: .
command: >
sh -c "python manage.py migrate &&
python manage.py createsuperuser_if_not_exists &&
python manage.py collectstatic --noinput &&
gunicorn mail_management.wsgi:application --bind 0.0.0.0:8000"
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/media
ports:
- "8000:8000"
env_file:
- .env
volumes:
static_volume:
media_volume:

View File

@@ -11,7 +11,7 @@ https://docs.djangoproject.com/en/5.2/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
@@ -20,13 +20,13 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-u^7rwn!f0*brki9f46&lu8_lal=3_(1kykx#84dp^hx62923qr'
SECRET_KEY = os.getenv("SECRET_KEY", 'django-insecure-u^7rwn!f0*brki9f46&lu8_lal=3_(1kykx#84dp^hx62923qr')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
DEBUG = os.getenv('DEBUG', 'false').lower() == 'true'
ALLOWED_HOSTS: list[str] = os.getenv('ALLOWED_HOSTS', '').split(',') if os.getenv('ALLOWED_HOSTS') else ['*']
CORS_ALLOWED_ORIGINS = os.getenv('CORS_ALLOWED_ORIGINS', '').split(',') if os.getenv('CORS_ALLOWED_ORIGINS') else []
# Application definition
@@ -39,17 +39,20 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'ninja_extra',
'ninja_jwt',
'corsheaders',
'api'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
]
ROOT_URLCONF = 'mail_management.urls'
@@ -119,6 +122,11 @@ USE_TZ = True
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = 'static/'
MEDIA_URL = '/media/'
STATIC_ROOT = BASE_DIR / "staticfiles"
MEDIA_ROOT = BASE_DIR / "media"
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field

View File

@@ -5,8 +5,10 @@ description = "Add your description here"
requires-python = ">=3.13"
dependencies = [
"django>=5.2.1",
"django-cors-headers>=4.7.0",
"django-ninja>=1.4.1",
"django-ninja-jwt>=5.3.7",
"mypy>=1.15.0",
"ruff>=0.11.10",
"whitenoise>=6.9.0",
]

60
requirements.txt Normal file
View File

@@ -0,0 +1,60 @@
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml -o requirements.txt
annotated-types==0.7.0
# via pydantic
asgiref==3.8.1
# via
# django
# django-cors-headers
# django-ninja-extra
cffi==1.17.1
# via cryptography
contextlib2==21.6.0
# via django-ninja-extra
cryptography==45.0.3
# via pyjwt
django==5.2.1
# via
# mail-management (pyproject.toml)
# django-cors-headers
# django-ninja
# django-ninja-extra
# django-ninja-jwt
django-cors-headers==4.7.0
# via mail-management (pyproject.toml)
django-ninja==1.4.1
# via
# mail-management (pyproject.toml)
# django-ninja-extra
django-ninja-extra==0.30.0
# via django-ninja-jwt
django-ninja-jwt==5.3.7
# via mail-management (pyproject.toml)
injector==0.22.0
# via django-ninja-extra
mypy==1.15.0
# via mail-management (pyproject.toml)
mypy-extensions==1.1.0
# via mypy
pycparser==2.22
# via cffi
pydantic==2.11.5
# via django-ninja
pydantic-core==2.33.2
# via pydantic
pyjwt==2.10.1
# via django-ninja-jwt
ruff==0.11.11
# via mail-management (pyproject.toml)
sqlparse==0.5.3
# via django
typing-extensions==4.13.2
# via
# mypy
# pydantic
# pydantic-core
# typing-inspection
typing-inspection==0.4.1
# via pydantic
whitenoise==6.9.0
# via mail-management (pyproject.toml)

26
uv.lock generated
View File

@@ -100,6 +100,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/90/92/7448697b5838b3a1c6e1d2d6a673e908d0398e84dc4f803a2ce11e7ffc0f/django-5.2.1-py3-none-any.whl", hash = "sha256:a9b680e84f9a0e71da83e399f1e922e1ab37b2173ced046b541c72e1589a5961", size = 8301833 },
]
[[package]]
name = "django-cors-headers"
version = "4.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "django" },
]
sdist = { url = "https://files.pythonhosted.org/packages/93/6c/16f6cb6064c63074fd5b2bd494eb319afd846236d9c1a6c765946df2c289/django_cors_headers-4.7.0.tar.gz", hash = "sha256:6fdf31bf9c6d6448ba09ef57157db2268d515d94fc5c89a0a1028e1fc03ee52b", size = 21037 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/a2/7bcfff86314bd9dd698180e31ba00604001606efb518a06cca6833a54285/django_cors_headers-4.7.0-py3-none-any.whl", hash = "sha256:f1c125dcd58479fe7a67fe2499c16ee38b81b397463cf025f0e2c42937421070", size = 12794 },
]
[[package]]
name = "django-ninja"
version = "1.4.1"
@@ -158,19 +171,23 @@ version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "django" },
{ name = "django-cors-headers" },
{ name = "django-ninja" },
{ name = "django-ninja-jwt" },
{ name = "mypy" },
{ name = "ruff" },
{ name = "whitenoise" },
]
[package.metadata]
requires-dist = [
{ name = "django", specifier = ">=5.2.1" },
{ name = "django-cors-headers", specifier = ">=4.7.0" },
{ name = "django-ninja", specifier = ">=1.4.1" },
{ name = "django-ninja-jwt", specifier = ">=5.3.7" },
{ name = "mypy", specifier = ">=1.15.0" },
{ name = "ruff", specifier = ">=0.11.10" },
{ name = "whitenoise", specifier = ">=6.9.0" },
]
[[package]]
@@ -330,3 +347,12 @@ sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be76
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 },
]
[[package]]
name = "whitenoise"
version = "6.9.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b9/cf/c15c2f21aee6b22a9f6fc9be3f7e477e2442ec22848273db7f4eb73d6162/whitenoise-6.9.0.tar.gz", hash = "sha256:8c4a7c9d384694990c26f3047e118c691557481d624f069b7f7752a2f735d609", size = 25920 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/64/b2/2ce9263149fbde9701d352bda24ea1362c154e196d2fda2201f18fc585d7/whitenoise-6.9.0-py3-none-any.whl", hash = "sha256:c8a489049b7ee9889617bb4c274a153f3d979e8f51d2efd0f5b403caf41c57df", size = 20161 },
]