diff --git a/README.md b/README.md index fc7e26c..ea1e6a3 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ poetry add django-base-settings In your Django settings file, define a subclass of `DjangoBaseSettings`: ```python +from django_base_settings import DjangoBaseSettings + class MySiteSettings(DjangoBaseSettings): allowed_hosts: list[str] = ["www.example.com"] debug: bool = False @@ -39,7 +41,74 @@ DEBUG = False DEFAULT_FROM_EMAIL = "webmaster@example.com" ``` -Field names in `DjangoBaseSettings` are case-insensitive and can be overridden through environment variables. +### Nested Settings + +For more complex configurations, you can define nested settings using Pydantic models: + +```python +from pydantic import Field +from pydantic_settings import BaseSettings + +from django_base_settings import DjangoBaseSettings + +class CacheSettings(BaseSettings): + backend: str = Field("django.core.cache.backends.redis.RedisCache", alias="BACKEND") + location: str = Field("redis://127.0.0.1:6379/1", alias="LOCATION") + +class MySiteSettings(DjangoBaseSettings): + caches: dict[str, CacheSettings] = { + "default": CacheSettings() + } + +my_site_settings = MySiteSettings() +``` + +This configuration is equivalent to: + +```python +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.redis.RedisCache", + "LOCATION": "redis://127.0.0.1:6379/1", + } +} +``` + +### Environment Variables + +Fields contained within DjangoBaseSettings and BaseSettings objects can be assigned values or have their default overwritten through environment variables, providing flexibility for different deployment environments. + +In this example: + +```python +from django_base_settings import DjangoBaseSettings + +class MySiteSettings(DjangoBaseSettings): + default_from_email: str = "webmaster@example.com" + +my_site_settings = MySiteSettings() +``` + +You can configure the value of default_from_email by creating an environment variable, which will overwrite the default value: + +```bash +export DEFAULT_FROM_EMAIL="admin@example.com" +``` + +You can also specify a different environment variable name: + +```python +from pydantic import Field + +from django_base_settings import DjangoBaseSettings + +class MySiteSettings(DjangoBaseSettings): + default_from_email: str = Field("webmaster@example.com", env="DEFAULT_EMAIL") + +my_site_settings = MySiteSettings() +``` + +In this example, setting `DEFAULT_EMAIL` as an environment variable will override the default value of `default_from_email`. ## License diff --git a/django_base_settings/django_base_settings.py b/django_base_settings/django_base_settings.py index ece0816..3c615d1 100644 --- a/django_base_settings/django_base_settings.py +++ b/django_base_settings/django_base_settings.py @@ -1,5 +1,6 @@ import sys +from pydantic import BaseModel from pydantic_settings import BaseSettings @@ -35,10 +36,20 @@ class MySiteSettings(DjangoBaseSettings): def __init__(self) -> None: super().__init__() - # Get the module where this instance was created module = sys.modules[self.__class__.__module__] - # Inject validated fields as module-level variables - for field_name, field_value in self.model_dump().items(): - setattr(module, field_name.upper(), field_value) + self._inject_settings(module, self) + + def _inject_settings(self, module, settings: BaseSettings) -> None: + for field_name, field_value in settings.model_dump(by_alias=True).items(): + # For nested models, inject a dictionary representation + if isinstance(field_value, (BaseSettings, BaseModel)): + setattr( + module, + field_name.upper(), + field_value.model_dump(by_alias=True), + ) + else: + # For regular fields, inject the value directly + setattr(module, field_name.upper(), field_value) diff --git a/pyproject.toml b/pyproject.toml index a7d0356..ced3f47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-base-settings" -version = "1.0.0" +version = "0.2.0" description = "Use Pydantic to enhance your Django application settings." authors = ["vsakkas "] license = "MIT"