Metadata-Version: 2.4
Name: django-nublado-core
Version: 0.4.1
Summary: A Django app for common configuration, utilities, and base models.
Author: C Nublado
License-Expression: BSD-3-Clause
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django>=5.0
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-django; extra == "test"
Requires-Dist: pytest-mock; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: pytest-html; extra == "test"
Requires-Dist: psycopg; extra == "test"
Dynamic: license-file

# django-nublado-core

**Common abstract models, utilities, and a simple dictionary-based app settings system for Django projects.**

## Overview

I found myself copying and pasting the same "core" app containing common abstract models, utilities, and app settings configuration in my Django projects, so I made it a reusable package.

The goal is to provide simple, reliable core building blocks without introducing unnecessary complexity. The package evolves incrementally as needs arise in my projects, and is shared for others who may find it useful.

## What’s included

- Abstract base models for common Django patterns (timestamps, UUIDs, language).
- A small utility for typed, dictionary-based application settings using dataclasses.

## Installation

Install the package from PyPI.

```bash
pip install django-nublado-core
```

Add the app to your Django project.

```python
INSTALLED_APPS = [
    ...
    "django_nublado_core",
]
```

The package provides only abstract models and utilities, and does not create database tables or migrations on its own.

## Abstract models

These core abstract models provide common fields and related functionality used across multiple models.


### `ValidatedSaveModel`

An abstract model that provides an explicit helper to validate a subclassed object
before saving it, without overriding the model's save method and inadvertently
messing something up.

This is especially useful in cases where you want to ensure model validation is applied outside of Django forms.

```python
from django.db import models

from django_nublado_core.models import ValidatedSaveModel


class Article(ValidatedSaveModel):
    title = models.CharField(max_length=200)


# Sample usage
article = Article(title="hello there")
# full_clean and save
article.validate_and_save()
```

#### Notes
- Calls `full_clean()` before saving.
- Does not override Django’s `save()` method.
- Useful for explicit validation outside of forms when saving.


### `TimestampModel`

An abstract model that adds automatic timestamp fields for object creation and updates.

```python
from django.db import models

from django_nublado_core.models import TimestampModel


class Article(TimestampModel):
    title = models.CharField(max_length=200)


# Sample usage
article = Article(title="hello there")
article.save()
article.created_at
article.updated_at # refreshed on each save
```

#### Notes
- Uses timezone-aware datetimes.

**Fields:**
- `created_at`
- `updated_at`

### `UUIDModel`

An abstract model that generates a UUID for a subclassed model's primary key.

```python
from django.db import models

from django_nublado_core.models import UUIDModel


class User(UUIDModel):
    username = models.CharField(max_length=200)

# Sample usage
user = User(username="Paco")
user.save()
# Primary key is a generated UUID.
user.pk # UUID('eeb4a289-034c-4e4c-9c54-98100cca1ee7')

```

#### Notes
- The generated UUID field is set as the **primary key**.

### `LanguageModel`

An abstract model that provides a language choices
field populated by the project's language settings.


`LanguageModel` contains an inner `LanguageChoices` enum derived from `settings.LANGUAGES`.

```python
from django.db import models

from django_nublado_core.models import LanguageModel


class Article(LanguageModel):
    title = models.CharField(max_length=200)


# Sample usage
article = Article(title="hello there")
article.save()
article.language # "en"

article.LanguageChoices.EN.value # "en"
```

#### Notes
- The default language value is taken from `settings.LANGUAGE_CODE`.
- Language values are validated via `full_clean()`, but are not enforced at the database level by default. This is intentional. Database-level constraints can be added in subclasses if needed.


## Application settings

This package provides a small utility for loading typed, dictionary-based
application settings using Django settings and Python dataclasses.

To configure settings for an app, define three things in a module
(`conf.py` or `app_settings.py` for example):

- The name of the settings dictionary
- A dictionary of default values
- A dataclass defining the exposed settings

### Defining app settings

```python
from dataclasses import dataclass

from django_nublado_core.conf.base import AppSettings

# The app's settings dict name (defined in Django settings.py)
SETTINGS_DICT_NAME = "YOUR_APP_SETTINGS"

# Default values for all exposed settings
SETTINGS_DEFAULTS = {
    "SETTING_A": "setting A",
}


@dataclass(frozen=True)
class AppData:
    SETTING_A: str


app_settings = AppSettings(
    settings_dict_name=SETTINGS_DICT_NAME,
    defaults=SETTINGS_DEFAULTS,
    cls=AppData,
)
```

### Overriding settings

In your project's `settings.py`, define a dictionary matching the configured settings name.

```python
YOUR_APP_SETTINGS = {
    "SETTING_A": "custom value",
}
```

Only keys explicitly declared on the dataclass are loaded. Unknown keys are
ignored and logged as warnings.

### Usage

The resulting `app_settings` object provides typed, read-only access
to your application settings.

```python
from .config import app_settings

value = app_settings.SETTING_A
```

#### Notes

- All settings must have defaults defined.
- Settings are loaded and cached at runtime.
- Unknown user-defined keys are ignored and logged.
- The resulting settings object is immutable.


## Testing

```bash
pytest
```

#### Notes:
- Runs all tests for the app.
- Requires `pytest-django`.
