File size: 7,613 Bytes
24e6f5b 9582e8b 24e6f5b 9582e8b 24e6f5b 9582e8b ddde0db 24e6f5b 9582e8b 24e6f5b 9582e8b 24e6f5b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | """
Django settings for expense_tracker project.
Generated by 'django-admin startproject' using Django 5.2.10.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
from pathlib import Path
import os
from dotenv import load_dotenv
load_dotenv()
# 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/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('SECRET_KEY', 'django-insecure-ereyyk0#@t#lc$@hpx&9h@60-=-e+#=-3w^w+91w&ol-(6c(fv')
# FIX: InsecureKeyLengthWarning for JWT (needs 32 bytes)
# If the user-provided key is too short (e.g. 23 chars), we safely pad it for the runtime.
if len(SECRET_KEY) < 32:
import logging
print(f"WARNING: SECRET_KEY is too short ({len(SECRET_KEY)} chars). key_fix=True")
# Pad with a consistent salt so it doesn't invalidate tokens on every restart if the base key is constant
SECRET_KEY = SECRET_KEY.ljust(32, '-')
# SECURITY WARNING: don't run with debug turned on in production!
# SECURITY WARNING: don't run with debug turned on in production!
ENVIRONMENT = os.getenv('ENVIRONMENT', 'development')
DEBUG = os.getenv('DEBUG', 'False') == 'True'
# Combine the default hosts into a single string string
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost,127.0.0.1,0.0.0.0,finmk.koyeb.app,finmk.onrender.com').split(',')
ALLOWED_HOSTS.append('.hf.space')
RENDER_EXTERNAL_HOSTNAME = os.environ.get('RENDER_EXTERNAL_HOSTNAME')
if RENDER_EXTERNAL_HOSTNAME:
ALLOWED_HOSTS.append(RENDER_EXTERNAL_HOSTNAME)
# Always allow .onrender.com in production-like environments or if explicitly set
if ENVIRONMENT == 'production' or RENDER_EXTERNAL_HOSTNAME:
ALLOWED_HOSTS.append('.koyeb.app')
ALLOWED_HOSTS.append('.onrender.com')
# Render health checks sometimes use raw IPs or localhost, which are covered above.
# CSRF_TRUSTED_ORIGINS required for Render and Hugging Face
CSRF_TRUSTED_ORIGINS = [
'https://finmk.koyeb.app',
'https://finmk.onrender.com',
'https://*.hf.space',
'https://kumar715-finmk.hf.space'
]
if RENDER_EXTERNAL_HOSTNAME:
CSRF_TRUSTED_ORIGINS.append(f'https://{RENDER_EXTERNAL_HOSTNAME}')
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third-party
'rest_framework',
'corsheaders',
# Local
'users',
'finance',
'analytics',
'chatbot',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'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',
]
ROOT_URLCONF = 'expense_tracker.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'staticfiles'],
'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 = 'expense_tracker.wsgi.application'
# Database
# HYBRID ARCHITECTURE:
# 1. 'default' (SQLite): Used ONLY for Django Admin, Auth, Sessions, ContentTypes.
# Controlled by 'expense_tracker.db_router.AuthRouter'.
# 2. MongoDB (PyMongo): Used as the PRIMARY database for all application data (Users, Finance, Analytics).
# Accessed directly via 'utils.MongoDBClient' and 'users.mongo_auth'.
# NO Django ORM models are used for application data.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
DATABASE_ROUTERS = ['expense_tracker.db_router.AuthRouter']
# MongoDB Settings (Primary Data Source for App)
MONGODB_URI = os.getenv('MONGODB_URI', 'mongodb+srv://kumar:KumarDB7@mkcluster.hkk76.mongodb.net/finance')
MONGODB_SETTINGS = {
'URI': MONGODB_URI,
'DB_NAME': 'finance',
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
# AUTH_PASSWORD_VALIDATORS commented out as we are in 100% MongoDB mode
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.2/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.2/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
# Add frontend/dist to static files directories
STATICFILES_DIRS = []
if (BASE_DIR / '../frontend/dist').exists():
STATICFILES_DIRS.append(BASE_DIR / '../frontend/dist')
# Docker build path
if (BASE_DIR / 'frontend_build').exists():
STATICFILES_DIRS.append(BASE_DIR / 'frontend_build')
# Whitenoise configuration for serving static files
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
# CORS Configuration
if DEBUG:
CORS_ALLOW_ALL_ORIGINS = True
else:
CORS_ALLOWED_ORIGINS = [
"https://finmk.koyeb.app","https://finmk.onrender.com" # Update with your actual domain
]
# Allow all subdomains for flexibility
CORS_ALLOWED_ORIGIN_REGEXES = [
r"^https://.*\.koyeb\.app$",
r"^https://.*\.onrender\.com$",
r"^https://.*\.hf\.space$"
]
CORS_ALLOW_CREDENTIALS = True
# AUTH_USER_MODEL = 'users.User' # Custom user model (Disabled as we use MongoUser)
AUTHENTICATION_BACKENDS = [
'users.mongo_auth.MongoBackend', # For App (MongoDB) - Primary
'django.contrib.auth.backends.ModelBackend', # For Admin (SQLite) - Secondary
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'users.authentication.MongoJWTAuthentication', # For Mongo Users (App) - Priority
'rest_framework_simplejwt.authentication.JWTAuthentication', # For SQLite Users (Admin)
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'USER_ID_CLAIM': 'user_id',
}
# Database config moved to standard location above
|