diff --git a/.env.sample b/.env.sample index fabf173..b8ebd53 100644 --- a/.env.sample +++ b/.env.sample @@ -28,4 +28,18 @@ BACKEND_SMTP_AUTH_PASSWORD="inbucket" BACKEND_SMTP_FROM_ADDRESS="admin@test.com" # docker-compose.yml -BACKEND_PORT=8000 \ No newline at end of file +BACKEND_PORT=8000 + +# Cache +BACKEND_CACHE_HOST="redis" +BACKEND_CACHE_PORT="6379" +BACKEND_CACHE_USERNAME="REPLACE-ME" +BACKEND_CACHE_PASSWORD="REPLACE-ME" + +# DEBUG Variables: Only used in development +BACKEND_PASSWORD="REPLACE-ME" + + +# # CACHE +CACHE_USERNAME="REPLACE-ME" +CACHE_PASSWORD="REPLACE-ME" \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 104417b..3d4d0d8 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -13,6 +13,15 @@ services: volumes: - ./src:/app/src # NOTE: Do not hot reload the entire /app folder as it will break the .venv + # Cache + redis: + image: redis:latest + restart: always + environment: + - REDIS_USERNAME=${CACHE_USERNAME} + - REDIS_PASSWORD=${CACHE_PASSWORD} + - REDIS_DISABLE_DEFAULT_USER="true" + # Email Testing Server # http://localhost:8025 inbucket: @@ -27,4 +36,3 @@ services: - INBUCKET_WEB_ADDR=0.0.0.0:8025 - INBUCKET_STORAGE_TYPE=memory - INBUCKET_STORAGE_MAILBOXMSGCAP=2000 - diff --git a/docker-compose.yml b/docker-compose.yml index 3832a82..cc89d47 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,9 +6,19 @@ services: context: . dockerfile: Dockerfile image: git.06222001.xyz/keannu125/drf_template:latest + restart: always ports: - "${BACKEND_PORT}:8000" environment: - RUN_TYPE=api volumes: - - ./src:/app/src # Bind mount for persistent schema.yml and static files \ No newline at end of file + - ./src:/app/src # Bind mount for persistent schema.yml and static files + + # Cache + redis: + image: redis:latest + restart: always + environment: + - REDIS_USERNAME=${CACHE_USERNAME} + - REDIS_PASSWORD=${CACHE_PASSWORD} + - REDIS_DISABLE_DEFAULT_USER="true" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index f892199..bdcf989 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,4 +22,5 @@ dependencies = [ "django-unfold>=0.65.0", "gunicorn>=23.0.0", "django-cors-headers>=4.7.0", + "django-redis>=6.0.0", ] diff --git a/src/core/config/models.py b/src/core/config/models.py index 19adb68..9e3cf52 100644 --- a/src/core/config/models.py +++ b/src/core/config/models.py @@ -43,8 +43,10 @@ class Config(BaseModel): default=False, description="Whether to serve media files locally as oppossed to using a cloud storage solution.", ) - SMTP_HOST: StrictStr = Field(required=True, description="SMTP server address") - SMTP_PORT: int = Field(default=587, description="SMTP server port (default: 587)") + SMTP_HOST: StrictStr = Field( + required=True, description="SMTP server address") + SMTP_PORT: int = Field( + default=587, description="SMTP server port (default: 587)") SMTP_USE_TLS: bool = Field( default=True, description="Whether to use TLS for SMTP connections" ) @@ -66,6 +68,18 @@ class Config(BaseModel): DEBUG_USER_PASSWORD: StrictStr = Field( required=True, description="Password for test users created during development" ) + CACHE_USERNAME: StrictStr = Field( + required=True, description="Cache server authentication username" + ) + CACHE_PASSWORD: StrictStr = Field( + required=True, description="Cache server authentication password" + ) + CACHE_HOST: StrictStr = Field( + required=True, description="Server host used for caching" + ) + CACHE_PORT: int = Field( + required=True, description="Server port used for caching" + ) @field_validator("CORS_ORIGINS", "ALLOWED_HOSTS", mode="before") def parse_list(cls, v): diff --git a/src/core/settings.py b/src/core/settings.py index c8eb090..f15a8be 100644 --- a/src/core/settings.py +++ b/src/core/settings.py @@ -242,8 +242,21 @@ SPECTACULAR_SETTINGS = { "SERVE_INCLUDE_SCHEMA": False, } + # Pygraphviz GRAPH_MODELS = { "all_applications": True, "group_models": True, } + + +# Caching +CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": f"redis://{config.CACHE_USERNAME}:{config.CACHE_PASSWORD}@{config.CACHE_HOST}:{config.CACHE_PORT}/1", + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + }, + } +} diff --git a/uv.lock b/uv.lock index b67c71a..d3c71ab 100644 --- a/uv.lock +++ b/uv.lock @@ -235,6 +235,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/96/d967ca440d6a8e3861120f51985d8e5aec79b9a8bdda16041206adfe7adc/django_extensions-4.1-py3-none-any.whl", hash = "sha256:0699a7af28f2523bf8db309a80278519362cd4b6e1fd0a8cd4bf063e1e023336", size = 232980, upload-time = "2025-04-11T01:15:37.701Z" }, ] +[[package]] +name = "django-redis" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "redis" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/53/dbcfa1e528e0d6c39947092625b2c89274b5d88f14d357cee53c4d6dbbd4/django_redis-6.0.0.tar.gz", hash = "sha256:2d9cb12a20424a4c4dde082c6122f486628bae2d9c2bee4c0126a4de7fda00dd", size = 56904, upload-time = "2025-06-17T18:15:46.376Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/79/055dfcc508cfe9f439d9f453741188d633efa9eab90fc78a67b0ab50b137/django_redis-6.0.0-py3-none-any.whl", hash = "sha256:20bf0063a8abee567eb5f77f375143c32810c8700c0674ced34737f8de4e36c0", size = 33687, upload-time = "2025-06-17T18:15:34.165Z" }, +] + [[package]] name = "django-rest-framework" version = "0.1.0" @@ -358,6 +371,7 @@ dependencies = [ { name = "django" }, { name = "django-cors-headers" }, { name = "django-extensions" }, + { name = "django-redis" }, { name = "django-rest-framework" }, { name = "django-silk" }, { name = "django-unfold" }, @@ -379,6 +393,7 @@ requires-dist = [ { name = "django", specifier = ">=5.2.5" }, { name = "django-cors-headers", specifier = ">=4.7.0" }, { name = "django-extensions", specifier = ">=4.1" }, + { name = "django-redis", specifier = ">=6.0.0" }, { name = "django-rest-framework", specifier = ">=0.1.0" }, { name = "django-silk", specifier = ">=5.4.2" }, { name = "django-unfold", specifier = ">=0.65.0" }, @@ -635,6 +650,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, ] +[[package]] +name = "redis" +version = "6.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399, upload-time = "2025-08-07T08:10:11.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847, upload-time = "2025-08-07T08:10:09.84Z" }, +] + [[package]] name = "referencing" version = "0.36.2"