diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c72df84..ac7f3c6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -18,11 +18,17 @@ }, // Add the IDs of extensions you want installed when the container is created. "extensions": [ + "batisteo.vscode-django", "bpruitt-goddard.mermaid-markdown-syntax-highlighting", "DavidAnson.vscode-markdownlint", "eamodio.gitlens", "esbenp.prettier-vscode", "mhutchie.git-graph", + "monosans.djlint", + "ms-python.python", + "ms-python.black-formatter", + "ms-python.flake8", + "qwtel.sqlite-viewer", "tamasfe.even-better-toml" ] } diff --git a/.dockerignore b/.dockerignore index 3e715fd..3842b8d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ .git/ *.egg-info +*.db diff --git a/.env.sample b/.env.sample index 9472e86..ca0603f 100644 --- a/.env.sample +++ b/.env.sample @@ -1,3 +1,7 @@ +# Django storage +DJANGO_STORAGE_DIR=. +DJANGO_DB_FILE=django.db + # uncomment to start the elasticstack services with compose # COMPOSE_PROFILES=elasticstack diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..0fdb3d0 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 127 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..fdd58d2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Django: PeMS Client", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": ["runserver", "--insecure", "0.0.0.0:8000"], + "django": true, + "env": { + "DJANGO_DEBUG": "true", + "PYTHONWARNINGS": "default" + } + }, + { + "name": "Django: PeMS Client, Debug=False", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": ["runserver", "--insecure", "0.0.0.0:8000"], + "django": true, + "env": { + "DJANGO_DEBUG": "false", + "DJANGO_STATICFILES_STORAGE": "django.contrib.staticfiles.storage.StaticFilesStorage" + } + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 40881c9..1698f7b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,9 @@ { + "[django-html][html]": { + "editor.defaultFormatter": "monosans.djlint", + "djlint.enableLinting": true, + "djlint.profile": "django" + }, "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "files.associations": { @@ -11,5 +16,12 @@ "files.trimTrailingWhitespace": true, "[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter" + }, + "python.languageServer": "Pylance", + "workbench.editorAssociations": { + "*.db": "sqlite-viewer.option" } } diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..12fddef --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pems.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/pems/settings.py b/pems/settings.py new file mode 100644 index 0000000..59b94c9 --- /dev/null +++ b/pems/settings.py @@ -0,0 +1,118 @@ +""" +Django settings for pems project. +""" + +from pathlib import Path +import os + + +def _filter_empty(ls): + return [s for s in ls if s] + + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "secret") + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = os.environ.get("DJANGO_DEBUG", "False").lower() == "true" + +ALLOWED_HOSTS = _filter_empty(os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")) + + +# 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 = "pems.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "pems.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +STORAGE_DIR = os.environ.get("DJANGO_STORAGE_DIR", BASE_DIR) +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": Path(STORAGE_DIR) / os.environ.get("DJANGO_DB_FILE", "django.db"), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.1/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/5.1/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/5.1/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/pems/urls.py b/pems/urls.py new file mode 100644 index 0000000..6d14891 --- /dev/null +++ b/pems/urls.py @@ -0,0 +1,23 @@ +""" +URL configuration for pems project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +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 + +urlpatterns = [ + path("admin/", admin.site.urls), +] diff --git a/pems/wsgi.py b/pems/wsgi.py new file mode 100644 index 0000000..059171f --- /dev/null +++ b/pems/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for pems project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pems.settings") + +application = get_wsgi_application() diff --git a/pyproject.toml b/pyproject.toml index 525cdd8..82f7ddc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ maintainers = [ { name = "Compiler LLC", email = "dev@compiler.la" } ] dependencies = [ + "Django==5.1.4" ] [project.optional-dependencies]