""" Django settings for {{ cookiecutter.project_slug }} project. Generated by 'django-admin startproject' using Django 5.1.6. For more information on this file, see https://docs.djangoproject.com/en/5.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/5.1/ref/settings/ """ from pathlib import Path import warnings import os try: import dotenv dotenv.load_dotenv() except ImportError: pass # Suppress deprecation warnings from third-party packages warnings.filterwarnings('ignore', category=UserWarning, module='dj_rest_auth') # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = os.getenv('SECRET_KEY', 'django-insecure-change-me-in-production') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = os.getenv('DEBUG', 'True').lower() in ('true', '1', 'yes') ALLOWED_HOSTS = [h.strip() for h in os.getenv('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',') if h.strip()] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.sites', # Third party apps 'authtools', 'rest_framework', 'rest_framework.authtoken', 'allauth', 'allauth.account', 'allauth.socialaccount', 'dj_rest_auth', 'dj_rest_auth.registration', 'django_cloud_tasks', # Local apps '{{ cookiecutter.project_slug }}', 'accounts', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', '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', 'allauth.account.middleware.AccountMiddleware', ] ROOT_URLCONF = '{{ cookiecutter.project_slug }}.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 = '{{ cookiecutter.project_slug }}.wsgi.application' # Database # https://docs.djangoproject.com/en/5.1/ref/settings/#databases # Default: PostgreSQL (recommended for production) # Set DATABASE_URL environment variable or configure below DATABASE_URL = os.getenv('DATABASE_URL') if DATABASE_URL: # Parse DATABASE_URL for production import dj_database_url DATABASES = { 'default': dj_database_url.parse(DATABASE_URL) } else: # Default to PostgreSQL for local development DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.getenv('DB_NAME', '{{ cookiecutter.project_slug }}'), 'HOST': os.getenv('DB_HOST', '127.0.0.1'), 'PORT': os.getenv('DB_PORT', '5432'), 'USER': os.getenv('DB_USER', 'postgres'), 'PASSWORD': os.getenv('DB_PASSWORD', 'postgres'), } } # Fallback to SQLite if USE_SQLITE is set (for quick local testing) if os.getenv('USE_SQLITE', '').lower() in ('true', '1', 'yes'): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # 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/' STATIC_ROOT = BASE_DIR / 'staticfiles' # Default primary key field type # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' SITE_ID = 1 # Custom User Model AUTH_USER_MODEL = 'accounts.User' # Django REST Framework Configuration REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.SessionAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', ], 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 20, } # Django Allauth Configuration ACCOUNT_LOGIN_METHODS = {'email'} ACCOUNT_SIGNUP_FIELDS = ['email*', 'password1*', 'password2*'] ACCOUNT_EMAIL_VERIFICATION = 'optional' ACCOUNT_CONFIRM_EMAIL_ON_GET = True ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True ACCOUNT_LOGOUT_ON_GET = True ACCOUNT_RATE_LIMITS = {'login_failed': '5/5m'} ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 3 ACCOUNT_PASSWORD_MIN_LENGTH = 8 # Configure allauth to work with email-only user model (no username) ACCOUNT_USER_MODEL_USERNAME_FIELD = None ACCOUNT_USER_MODEL_EMAIL_FIELD = 'email' # dj-rest-auth Configuration REST_AUTH_SERIALIZERS = { 'USER_DETAILS_SERIALIZER': 'accounts.api.serializers.UserDetailsSerializer', } REST_AUTH_REGISTER_SERIALIZERS = { 'REGISTER_SERIALIZER': 'accounts.api.serializers.CustomRegisterSerializer', } REST_USE_JWT = False REST_SESSION_LOGIN = False # Email Configuration (for development) EMAIL_BACKEND = os.getenv('EMAIL_BACKEND', 'django.core.mail.backends.console.EmailBackend') # Authentication backends AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', ] # S3/Backblaze B2 Storage Configuration (optional) {% if cookiecutter.use_s3_storage == 'y' %} USE_S3_STORAGE = os.getenv('USE_S3_STORAGE', '').lower() in ('true', '1', 'yes') {% endif %} if USE_S3_STORAGE: AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID") AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY") AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME") AWS_S3_ENDPOINT_URL = os.getenv("AWS_S3_ENDPOINT_URL") AWS_S3_REGION_NAME = os.getenv("AWS_S3_REGION_NAME") AWS_DEFAULT_ACL = None AWS_S3_FILE_OVERWRITE = False AWS_S3_VERIFY = True AWS_QUERYSTRING_AUTH = True AWS_QUERYSTRING_EXPIRE = 3600 AWS_S3_SIGNATURE_VERSION = 's3v4' AWS_S3_ADDRESSING_STYLE = 'virtual' STORAGES = { "default": {"BACKEND": "storages.backends.s3.S3Storage"}, "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"}, } else: STORAGES = { "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"}, "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"}, } # ============================================================================= # Django Cloud Tasks Configuration # ============================================================================= # In development, tasks run synchronously in-process (eager mode) # In production, configure GCP_PROJECT_ID and GCP_LOCATION for Cloud Tasks DJANGO_CLOUD_TASKS = { # Run tasks synchronously in development (no Cloud Tasks infrastructure needed) 'eager': os.getenv('CLOUD_TASKS_EAGER', 'True').lower() in ('true', '1', 'yes'), # GCP settings (used in production when eager=False) 'project_id': os.getenv('GCP_PROJECT_ID', ''), 'location': os.getenv('GCP_LOCATION', '{{ cookiecutter.gcp_region }}'), # Task queues with different priorities 'queues': { 'instant': { 'name': 'instant', }, 'high': { 'name': 'high', }, 'medium': { 'name': 'medium', }, 'low': { 'name': 'low', }, }, # Default queue for tasks without explicit queue 'default_queue': 'medium', }