| 
1 | 1 | import contextlib  | 
2 | 2 | import socket  | 
 | 3 | +from functools import partial  | 
 | 4 | +from pathlib import Path  | 
3 | 5 | 
 
  | 
4 |  | -import environs  | 
 | 6 | +from django.utils.crypto import get_random_string  | 
5 | 7 | 
 
  | 
6 |  | -env = environs.Env()  | 
 | 8 | +from django_envtools import Env  | 
7 | 9 | 
 
  | 
8 | 10 | """  | 
9 | 11 | Django settings for config project.  | 
10 | 12 | 
  | 
11 | 13 | For more information on this file, see  | 
12 |  | -https://docs.djangoproject.com/en/4.2/topics/settings/  | 
 | 14 | +https://docs.djangoproject.com/en/dev/topics/settings/  | 
13 | 15 | 
  | 
14 | 16 | For the full list of settings and their values, see  | 
15 |  | -https://docs.djangoproject.com/en/4.2/ref/settings/  | 
 | 17 | +https://docs.djangoproject.com/en/dev/ref/settings/  | 
16 | 18 | """  | 
17 | 19 | 
 
  | 
18 |  | -BASE_DIR = environs.Path(__file__).parent.parent.parent  # type: ignore  | 
 | 20 | + | 
 | 21 | +get_secret_key = partial(get_random_string, length=50, allowed_chars="abcdefghijklmnopqrstuvwxyz0123456789!@%^&*-_=")  | 
 | 22 | + | 
 | 23 | + | 
 | 24 | +BASE_DIR = Path(__file__).parent.parent.parent  # type: ignore  | 
 | 25 | + | 
 | 26 | +env = Env()  | 
19 | 27 | 
 
  | 
20 | 28 | READ_DOT_ENV_FILE = env.bool("READ_DOT_ENV_FILE", default=True)  | 
21 | 29 | 
 
  | 
22 | 30 | if READ_DOT_ENV_FILE is True:  | 
23 | 31 |     env.read_env(str(BASE_DIR.joinpath(".env")))  | 
24 | 32 | 
 
  | 
25 | 33 | # Quick-start development settings - unsuitable for production  | 
26 |  | -# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/  | 
 | 34 | +# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/  | 
27 | 35 | 
 
  | 
28 | 36 | # SECURITY WARNING: keep the secret key used in production secret!  | 
29 |  | -SECRET_KEY = env("SECRET_KEY")  | 
 | 37 | +SECRET_KEY = env.str(  | 
 | 38 | +    "SECRET_KEY",  | 
 | 39 | +    help_text="Django's secret key, see"  | 
 | 40 | +    "https://docs.djangoproject.com/en/dev/ref/settings/#secret-key for more information",  | 
 | 41 | +    initial_func=get_secret_key,  | 
 | 42 | +)  | 
30 | 43 | 
 
  | 
31 | 44 | # SECURITY WARNING: don't run with debug turned on in production!  | 
32 |  | -DEBUG = env.bool("DEBUG", default=False)  | 
 | 45 | +DEBUG = env.bool("DEBUG", default=False, initial="on", help_text="Set to `on` to enable debugging")  | 
 | 46 | + | 
 | 47 | +ALLOWED_HOSTS = env.list(  | 
 | 48 | +    "ALLOWED_HOSTS",  | 
 | 49 | +    default=[],  | 
 | 50 | +    help_text="List of allowed hosts (e.g., `127.0.0.1,example.com`), see "  | 
 | 51 | +    "https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts for more information",  | 
 | 52 | +)  | 
33 | 53 | 
 
  | 
34 |  | -ALLOWED_HOSTS: list[str] = env.list("ALLOWED_HOSTS", default=[])  | 
35 |  | -INTERNAL_IPS = env.list("INTERNAL_IPS", default=["127.0.0.1"])  | 
 | 54 | +INTERNAL_IPS = env.list(  | 
 | 55 | +    "INTERNAL_IPS",  | 
 | 56 | +    default=["127.0.0.1"],  | 
 | 57 | +    initial="127.0.0.1,0.0.0.0",  | 
 | 58 | +    help_text="IPs that are allowed to use debug() (e.g., `127.0.0.1,example.com`), see "  | 
 | 59 | +    "https://docs.djangoproject.com/en/dev/ref/settings/#internal-ips for more information",  | 
 | 60 | +)  | 
36 | 61 | 
 
  | 
37 | 62 | # Get the IP to use for Django Debug Toolbar when developing with docker  | 
38 |  | -if env.bool("USE_DOCKER", default=False) is True:  | 
 | 63 | +if (  | 
 | 64 | +    env.bool(  | 
 | 65 | +        "USE_DOCKER", default=False, help_text="Boolean used to add docker's internal ip to the `INTERNAL_IPS` setting"  | 
 | 66 | +    )  | 
 | 67 | +    is True  | 
 | 68 | +):  | 
39 | 69 |     ip = socket.gethostbyname(socket.gethostname())  | 
40 | 70 |     INTERNAL_IPS += [ip[:-1] + "1"]  | 
41 | 71 | 
 
  | 
 | 
56 | 86 |     "allauth.account",  | 
57 | 87 |     "crispy_forms",  | 
58 | 88 |     "crispy_bootstrap5",  | 
 | 89 | +    "django_envtools",  | 
59 | 90 |     "storages",  | 
60 | 91 | ]  | 
61 | 92 | 
 
  | 
 | 
92 | 123 |     },  | 
93 | 124 | ]  | 
94 | 125 | 
 
  | 
95 |  | -WSGI_APPLICATION = env("WSGI_APPLICATION", default="config.wsgi.application")  | 
96 |  | -DB_SSL_REQUIRED = env.bool("DB_SSL_REQUIRED", default=not DEBUG)  | 
 | 126 | +WSGI_APPLICATION = env.str(  | 
 | 127 | +    "WSGI_APPLICATION",  | 
 | 128 | +    default="config.wsgi.application",  | 
 | 129 | +    help_text="WSGI application callable, see https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application for "  | 
 | 130 | +    "more information",  | 
 | 131 | +)  | 
 | 132 | +DB_SSL_REQUIRED = env.bool(  | 
 | 133 | +    "DB_SSL_REQUIRED",  | 
 | 134 | +    default=not DEBUG,  | 
 | 135 | +    help_text="Set to `on` to require SSL for database connections, default is `off` when DEBUG is `on`",  | 
 | 136 | +)  | 
97 | 137 | 
 
  | 
98 |  | -# Database  | 
99 |  | -# See https://github.com/jacobian/dj-database-url for more examples  | 
100 | 138 | DATABASES = {  | 
101 | 139 |     "default": env.dj_db_url(  | 
102 |  | -        "DATABASE_URL", default="postgres://postgres@postgres/postgres", ssl_require=DB_SSL_REQUIRED  | 
 | 140 | +        "DATABASE_URL",  | 
 | 141 | +        default="postgres://postgres@postgres/postgres",  | 
 | 142 | +        ssl_require=DB_SSL_REQUIRED,  | 
 | 143 | +        initial="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}",  | 
 | 144 | +        help_text="Database URL for the default database, see https://github.com/jacobian/dj-database-url for "  | 
 | 145 | +        "more examples",  | 
103 | 146 |     )  | 
104 | 147 | }  | 
105 | 148 | 
 
  | 
106 | 149 | # Custom User Model  | 
107 |  | -# https://docs.djangoproject.com/en/4.2/topics/auth/customizing/#substituting-a-custom-user-model  | 
 | 150 | +# https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model  | 
108 | 151 | AUTH_USER_MODEL = "accounts.User"  | 
109 | 152 | 
 
  | 
110 | 153 | # Password validation  | 
111 |  | -# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators  | 
 | 154 | +# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators  | 
112 | 155 | 
 
  | 
113 | 156 | AUTH_PASSWORD_VALIDATORS = [  | 
114 | 157 |     {  | 
 | 
127 | 170 | 
 
  | 
128 | 171 | 
 
  | 
129 | 172 | # Internationalization  | 
130 |  | -# https://docs.djangoproject.com/en/4.2/topics/i18n/  | 
 | 173 | +# https://docs.djangoproject.com/en/dev/topics/i18n/  | 
131 | 174 | 
 
  | 
132 | 175 | LANGUAGE_CODE = "en-us"  | 
133 | 176 | 
 
  | 
 | 
140 | 183 | 
 
  | 
141 | 184 | 
 
  | 
142 | 185 | # Static files (CSS, JavaScript, Images)  | 
143 |  | -# https://docs.djangoproject.com/en/4.2/howto/static-files/  | 
 | 186 | +# https://docs.djangoproject.com/en/dev/howto/static-files/  | 
144 | 187 | 
 
  | 
145 | 188 | STATICFILES_FINDERS = (  | 
146 | 189 |     "django.contrib.staticfiles.finders.FileSystemFinder",  | 
147 | 190 |     "django.contrib.staticfiles.finders.AppDirectoriesFinder",  | 
148 | 191 | )  | 
149 | 192 | 
 
  | 
 | 193 | +DEFAULT_FILE_STORAGE = env.str(  | 
 | 194 | +    "DEFAULT_FILE_STORAGE",  | 
 | 195 | +    default="django.core.files.storage.FileSystemStorage",  | 
 | 196 | +    help_text="Default file storage backend, see https://docs.djangoproject.com/en/dev/ref/settings/#storages for "  | 
 | 197 | +    "more information",  | 
 | 198 | +)  | 
 | 199 | +STATICFILES_STORAGE = env.str(  | 
 | 200 | +    "DEFAULT_FILE_STORAGE",  | 
 | 201 | +    default="django.core.files.storage.FileSystemStorage",  | 
 | 202 | +    help_text="Default file storage for staticfiles, see https://docs.djangoproject.com/en/dev/ref/settings/#storages "  | 
 | 203 | +    "for more information",  | 
 | 204 | +)  | 
150 | 205 | STORAGES = {  | 
151 | 206 |     "default": {  | 
152 |  | -        "BACKEND": env("DEFAULT_FILE_STORAGE", default="django.core.files.storage.FileSystemStorage"),  | 
 | 207 | +        "BACKEND": DEFAULT_FILE_STORAGE,  | 
153 | 208 |     },  | 
154 | 209 |     "staticfiles": {  | 
155 |  | -        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",  | 
 | 210 | +        "BACKEND": STATICFILES_STORAGE,  | 
156 | 211 |     },  | 
157 | 212 | }  | 
158 | 213 | 
 
  | 
159 | 214 | 
 
  | 
160 | 215 | if STORAGES["default"]["BACKEND"].endswith("MediaS3Storage") is True:  | 
161 |  | -    STORAGES["staticfiles"]["BACKEND"] = env("STATICFILES_STORAGE")  | 
162 |  | -    AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID")  | 
163 |  | -    AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY")  | 
164 |  | -    AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME")  | 
 | 216 | +    STORAGES["staticfiles"]["BACKEND"] = STATICFILES_STORAGE  | 
 | 217 | +    AWS_ACCESS_KEY_ID = env.str("AWS_ACCESS_KEY_ID", help_text="AWS Access Key ID for S3 storage")  | 
 | 218 | +    AWS_SECRET_ACCESS_KEY = env.str("AWS_SECRET_ACCESS_KEY", help_text="AWS Secret Access Key for S3 storage")  | 
 | 219 | +    AWS_STORAGE_BUCKET_NAME = env.str("AWS_STORAGE_BUCKET_NAME", help_text="AWS S3 Bucket Name for storage")  | 
165 | 220 |     AWS_DEFAULT_ACL = "public-read"  | 
166 |  | -    AWS_S3_REGION = env("AWS_S3_REGION", default="us-east-2")  | 
 | 221 | +    AWS_S3_REGION = env.str("AWS_S3_REGION", default="us-east-1", help_text="AWS S3 Region for storage")  | 
167 | 222 |     AWS_S3_CUSTOM_DOMAIN = f"s3.{AWS_S3_REGION}.amazonaws.com/{AWS_STORAGE_BUCKET_NAME}"  | 
168 | 223 |     AWS_S3_OBJECT_PARAMETERS = {"CacheControl": "max-age=86400"}  | 
169 | 224 |     STATIC_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/static/"  | 
 | 
181 | 236 |     STATIC_URL = "/public/static/"  | 
182 | 237 | 
 
  | 
183 | 238 | # Default primary key field type  | 
184 |  | -# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field  | 
 | 239 | +# https://docs.djangoproject.com/en/dev/ref/settings/#default-auto-field  | 
185 | 240 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"  | 
186 | 241 | 
 
  | 
187 | 242 | # CACHE SETTINGS  | 
188 |  | -# Redis scheme docs: https://redis-py.readthedocs.io/en/stable/connections.html#redis.connection.ConnectionPool.from_url  | 
189 |  | -REDIS_URL = env("REDIS_URL", "redis://redis:6379/0")  | 
190 |  | -REDIS_PREFIX = env("REDIS_PREFIX", default="")  | 
 | 243 | +REDIS_URL = env.str(  | 
 | 244 | +    "REDIS_URL",  | 
 | 245 | +    default="redis://redis:6379/0",  | 
 | 246 | +    help_text="URL used to connect to Redis, see https://docs.djangoproject.com/en/dev/ref/settings/#location for "  | 
 | 247 | +    "more information",  | 
 | 248 | +)  | 
 | 249 | +REDIS_PREFIX = env.str(  | 
 | 250 | +    "REDIS_PREFIX",  | 
 | 251 | +    default="",  | 
 | 252 | +    help_text="Prefix for all Redis keys, useful to avoid key collisions in shared Redis instances",  | 
 | 253 | +)  | 
191 | 254 | CACHES = {  | 
192 | 255 |     "default": {  | 
193 | 256 |         "BACKEND": "django.core.cache.backends.redis.RedisCache",  | 
 | 
232 | 295 | ACCOUNT_SIGNUP_OPEN = False  | 
233 | 296 | ACCOUNT_SHOW_POST_LOGIN_MESSAGE = False  | 
234 | 297 | 
 
  | 
235 |  | -# See https://github.com/migonzalvar/dj-email-url for more examples on how to set the EMAIL_URL  | 
236 | 298 | email = env.dj_email_url(  | 
237 | 299 |     "EMAIL_URL",  | 
238 | 300 |     default="smtp://[email protected]:[email protected]:587/?ssl=True&_default_from_email=President%20Skroob%20%[email protected]%3E",   | 
 | 301 | +    help_text="Email URL for sending emails, see https://github.com/migonzalvar/dj-email-url for more examples",  | 
239 | 302 | )  | 
240 | 303 | DEFAULT_FROM_EMAIL = email["DEFAULT_FROM_EMAIL"]  | 
241 | 304 | EMAIL_HOST = email["EMAIL_HOST"]  | 
@@ -266,7 +329,7 @@ def log_format() -> str:  | 
266 | 329 | 
 
  | 
267 | 330 | 
 
  | 
268 | 331 | log_level = "WARNING"  | 
269 |  | -IS_DEBUG_LOGGING_ON = env.bool("IS_DEBUG_LOGGING_ON", default=False)  | 
 | 332 | +IS_DEBUG_LOGGING_ON = env.bool("IS_DEBUG_LOGGING_ON", default=False, help_text="Set to `on` to enable debug logging")  | 
270 | 333 | if IS_DEBUG_LOGGING_ON is True:  | 
271 | 334 |     log_level = "DEBUG"  | 
272 | 335 | 
 
  | 
@@ -305,4 +368,6 @@ def log_format() -> str:  | 
305 | 368 | MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.CacheBackend"  | 
306 | 369 | MAINTENANCE_MODE_STATE_BACKEND_FALLBACK_VALUE = True  | 
307 | 370 | 
 
  | 
308 |  | -VITE_DEV_MODE = env.bool("VITE_DEV_MODE", default=DEBUG)  | 
 | 371 | +VITE_DEV_MODE = env.bool(  | 
 | 372 | +    "VITE_DEV_MODE", default=DEBUG, help_text="Set to `on` to enable Vite development mode for HMR in the browser"  | 
 | 373 | +)  | 
0 commit comments