Metadata-Version: 2.4
Name: django-niceid
Version: 0.1.0
Summary: Namespaced UUIDv7 identifiers for Django, stored as PostgreSQL UUIDs
Project-URL: Homepage, https://github.com/owais/django-niceid
Project-URL: Documentation, https://github.com/owais/django-niceid#readme
Project-URL: Repository, https://github.com/owais/django-niceid
Project-URL: Issues, https://github.com/owais/django-niceid/issues
Project-URL: Changelog, https://github.com/owais/django-niceid/blob/main/CHANGELOG.md
Author-email: Owais Lone <owais@lone.id>
License-Expression: MIT
License-File: LICENSE
Keywords: django,identifier,primary-key,uuid,uuidv7
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.14
Requires-Dist: base32-crockford>=0.3.0
Requires-Dist: django<7,>=5.1
Provides-Extra: dev
Requires-Dist: django-ninja<2,>=1.3; extra == 'dev'
Requires-Dist: djangorestframework<4,>=3.15; extra == 'dev'
Requires-Dist: pre-commit>=4.0; extra == 'dev'
Requires-Dist: psycopg[binary]>=3.2; extra == 'dev'
Requires-Dist: pydantic<3,>=2.0; extra == 'dev'
Requires-Dist: pytest-django>=4.9; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Provides-Extra: drf
Requires-Dist: djangorestframework<4,>=3.15; extra == 'drf'
Provides-Extra: ninja
Requires-Dist: django-ninja<2,>=1.3; extra == 'ninja'
Provides-Extra: pydantic
Requires-Dist: pydantic<3,>=2.0; extra == 'pydantic'
Provides-Extra: tortoise
Requires-Dist: django-tortoise>=0.0.1; extra == 'tortoise'
Description-Content-Type: text/markdown

# django-niceid

Namespaced, Crockford base32-encoded **UUIDv7** identifiers for Django. IDs look like `user_1KGGWGM8FEABRJA533GJKYW0B` in Python and APIs, while PostgreSQL stores them as native **UUID** values (sortable, compact, index-friendly).

## Requirements

- **Python** 3.14+ (`uuid.uuid7` in the standard library)
- **Django** 5.1+
- **PostgreSQL 18+** with native UUID support and a built-in `uuidv7()` function

## Install

```bash
pip install django-niceid
```

Optional integrations:

```bash
pip install django-niceid[drf]      # Django REST Framework
pip install django-niceid[ninja]    # Django Ninja
pip install django-niceid[pydantic] # Pydantic v2 schemas
pip install django-niceid[tortoise] # django-tortoise ORM bridge
```

## Quickstart

Add the app to `INSTALLED_APPS`:

```python
INSTALLED_APPS = [
    # ...
    "niceid.apps.NiceIDConfig",
]
```

Define a model with a class-level `namespace` (2–16 lowercase letters or underscores):

```python
from niceid.models import NiceIDModel


class User(NiceIDModel):
    namespace = "user"

    class Meta:
        # your options
        pass
```

Each row gets a primary key like `user_1KGGWGM8FEABRJA533GJKYW0B`. The value is generated by PostgreSQL via `db_default=uuidv7()` and exposed in Python as a `NiceID` instance.

### PostgreSQL `uuidv7()`

On PostgreSQL 18+, `uuidv7()` is available without extra setup. Ensure your database supports it before running migrations:

```sql
SELECT uuidv7();
```

## URL converter

The app config registers a path converter named `niceid`:

```python
from django.urls import path

urlpatterns = [
    path("users/<niceid:user_id>/", user_detail),
]
```

`user_id` in the view is a `NiceID` instance.

## Optional integrations

### Django REST Framework

```python
from niceid.drf import NiceIDSerializerField, NiceIDRelatedField

class UserSerializer(serializers.ModelSerializer):
    id = NiceIDSerializerField(read_only=True)
    team_id = NiceIDRelatedField(queryset=Team.objects.all(), source="team")
```

### Django Ninja

Install `django-niceid[ninja]`. Field registration runs automatically in `NiceIDConfig.ready()`.

### Pydantic

Install `django-niceid[pydantic]`:

```python
from pydantic import BaseModel
from niceid import NiceID

class Payload(BaseModel):
    user_id: NiceID
```

## ID format

| Part        | Rule                                      |
|-------------|-------------------------------------------|
| Namespace   | `[a-z_]{2,16}`                            |
| Separator   | `_`                                       |
| Encoded UUID| 25 Crockford base32 characters (UUIDv7) |

Example: `user_1KGGWGM8FEABRJA533GJKYW0B`

## Limitations (v0.1.0)

- **PostgreSQL only** for database fields (native UUID column + `uuidv7()` default).
- **Python 3.14+** only.
- Non-primary-key `NiceIDField` usage requires an explicit `namespace=` on the field.

## Development

```bash
pip install -e ".[dev]"
pytest -m "not postgres"
docker compose up -d
POSTGRES_HOST=localhost POSTGRES_PORT=54329 pytest -m postgres
```

See [CONTRIBUTING.md](CONTRIBUTING.md).

## License

MIT — see [LICENSE](LICENSE).
