django-display-ids 0.1.2__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/PKG-INFO +15 -5
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/README.md +13 -3
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/pyproject.toml +3 -2
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/contrib/rest_framework/views.py +23 -2
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/models.py +6 -1
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/views.py +25 -2
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/__init__.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/admin.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/conf.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/contrib/__init__.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/contrib/rest_framework/__init__.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/encoding.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/exceptions.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/managers.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/py.typed +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/resolver.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/strategies.py +0 -0
- {django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/typing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: django-display-ids
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Stripe-like prefixed IDs for Django. Works with existing UUIDs — no schema changes.
|
|
5
5
|
Keywords: django,stripe,uuid,base62,prefixed-id,drf,shortuuid,nanoid,ulid
|
|
6
6
|
License: ISC
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
17
17
|
Classifier: Typing :: Typed
|
|
18
18
|
Requires-Dist: django>=4.2
|
|
19
19
|
Requires-Python: >=3.12
|
|
20
|
-
Project-URL:
|
|
20
|
+
Project-URL: Homepage, https://joseph.is/django-display-ids
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
23
|
# django-display-ids
|
|
@@ -34,6 +34,8 @@ This library focuses on **lookup only** — it works with your existing UUID fie
|
|
|
34
34
|
pip install django-display-ids
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
No `INSTALLED_APPS` entry required — just import and use.
|
|
38
|
+
|
|
37
39
|
## Quick Start
|
|
38
40
|
|
|
39
41
|
```python
|
|
@@ -249,11 +251,13 @@ The `display_id` strategy requires a prefix. If no prefix is configured, the str
|
|
|
249
251
|
|-----------|---------|-------------|
|
|
250
252
|
| `lookup_param` / `lookup_url_kwarg` | `"pk"` | URL parameter name |
|
|
251
253
|
| `lookup_strategies` | from settings | Strategies to try |
|
|
252
|
-
| `display_id_prefix` |
|
|
254
|
+
| `display_id_prefix` | from model | Expected prefix (falls back to model's `display_id_prefix`) |
|
|
253
255
|
| `uuid_field` | `"id"` | UUID field name on model |
|
|
254
256
|
| `slug_field` | `"slug"` | Slug field name on model |
|
|
255
257
|
|
|
256
|
-
### Django Settings
|
|
258
|
+
### Django Settings (Optional)
|
|
259
|
+
|
|
260
|
+
All settings have sensible defaults. Only add this if you need to override them:
|
|
257
261
|
|
|
258
262
|
```python
|
|
259
263
|
# settings.py
|
|
@@ -298,10 +302,16 @@ Run tests:
|
|
|
298
302
|
uv run pytest
|
|
299
303
|
```
|
|
300
304
|
|
|
305
|
+
Run tests with coverage:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
uv run pytest --cov=src/django_display_ids
|
|
309
|
+
```
|
|
310
|
+
|
|
301
311
|
Run tests across Python and Django versions:
|
|
302
312
|
|
|
303
313
|
```bash
|
|
304
|
-
uvx nox
|
|
314
|
+
uvx nox
|
|
305
315
|
```
|
|
306
316
|
|
|
307
317
|
Lint and format:
|
|
@@ -12,6 +12,8 @@ This library focuses on **lookup only** — it works with your existing UUID fie
|
|
|
12
12
|
pip install django-display-ids
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
No `INSTALLED_APPS` entry required — just import and use.
|
|
16
|
+
|
|
15
17
|
## Quick Start
|
|
16
18
|
|
|
17
19
|
```python
|
|
@@ -227,11 +229,13 @@ The `display_id` strategy requires a prefix. If no prefix is configured, the str
|
|
|
227
229
|
|-----------|---------|-------------|
|
|
228
230
|
| `lookup_param` / `lookup_url_kwarg` | `"pk"` | URL parameter name |
|
|
229
231
|
| `lookup_strategies` | from settings | Strategies to try |
|
|
230
|
-
| `display_id_prefix` |
|
|
232
|
+
| `display_id_prefix` | from model | Expected prefix (falls back to model's `display_id_prefix`) |
|
|
231
233
|
| `uuid_field` | `"id"` | UUID field name on model |
|
|
232
234
|
| `slug_field` | `"slug"` | Slug field name on model |
|
|
233
235
|
|
|
234
|
-
### Django Settings
|
|
236
|
+
### Django Settings (Optional)
|
|
237
|
+
|
|
238
|
+
All settings have sensible defaults. Only add this if you need to override them:
|
|
235
239
|
|
|
236
240
|
```python
|
|
237
241
|
# settings.py
|
|
@@ -276,10 +280,16 @@ Run tests:
|
|
|
276
280
|
uv run pytest
|
|
277
281
|
```
|
|
278
282
|
|
|
283
|
+
Run tests with coverage:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
uv run pytest --cov=src/django_display_ids
|
|
287
|
+
```
|
|
288
|
+
|
|
279
289
|
Run tests across Python and Django versions:
|
|
280
290
|
|
|
281
291
|
```bash
|
|
282
|
-
uvx nox
|
|
292
|
+
uvx nox
|
|
283
293
|
```
|
|
284
294
|
|
|
285
295
|
Lint and format:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "django-display-ids"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.3"
|
|
4
4
|
description = "Stripe-like prefixed IDs for Django. Works with existing UUIDs — no schema changes."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -34,12 +34,13 @@ dependencies = [
|
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
[project.urls]
|
|
37
|
-
|
|
37
|
+
Homepage = "https://joseph.is/django-display-ids"
|
|
38
38
|
|
|
39
39
|
[dependency-groups]
|
|
40
40
|
dev = [
|
|
41
41
|
"pytest>=8.0",
|
|
42
42
|
"pytest-django>=4.8",
|
|
43
|
+
"pytest-cov>=6.0",
|
|
43
44
|
"djangorestframework>=3.14",
|
|
44
45
|
"shortuuid>=1.0",
|
|
45
46
|
"nox>=2024.0",
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
from django_display_ids.conf import get_setting
|
|
8
|
+
from django_display_ids.encoding import PREFIX_PATTERN
|
|
8
9
|
from django_display_ids.exceptions import (
|
|
9
10
|
InvalidIdentifierError,
|
|
10
11
|
LookupError,
|
|
@@ -21,6 +22,8 @@ __all__ = [
|
|
|
21
22
|
"DisplayIDLookupMixin",
|
|
22
23
|
]
|
|
23
24
|
|
|
25
|
+
_NOT_SET: Any = object()
|
|
26
|
+
|
|
24
27
|
|
|
25
28
|
def _get_drf_exceptions() -> tuple[type[Exception], type[Exception]]:
|
|
26
29
|
"""Lazily import DRF exceptions to avoid hard dependency."""
|
|
@@ -68,7 +71,7 @@ class DisplayIDLookupMixin:
|
|
|
68
71
|
|
|
69
72
|
lookup_url_kwarg: str = "pk"
|
|
70
73
|
lookup_strategies: tuple[StrategyName, ...] | None = None
|
|
71
|
-
display_id_prefix: str | None =
|
|
74
|
+
display_id_prefix: str | None = _NOT_SET
|
|
72
75
|
uuid_field: str | None = None
|
|
73
76
|
slug_field: str | None = None
|
|
74
77
|
|
|
@@ -91,6 +94,24 @@ class DisplayIDLookupMixin:
|
|
|
91
94
|
return self.lookup_strategies
|
|
92
95
|
return get_setting("STRATEGIES") # type: ignore[return-value]
|
|
93
96
|
|
|
97
|
+
def _get_display_id_prefix(self, model: type[models.Model]) -> str | None:
|
|
98
|
+
"""Get the display ID prefix.
|
|
99
|
+
|
|
100
|
+
Returns the viewset's display_id_prefix if set (including None to
|
|
101
|
+
explicitly disable), otherwise falls back to the model's
|
|
102
|
+
display_id_prefix attribute.
|
|
103
|
+
"""
|
|
104
|
+
if self.display_id_prefix is not _NOT_SET:
|
|
105
|
+
if self.display_id_prefix is not None and not PREFIX_PATTERN.match(
|
|
106
|
+
self.display_id_prefix
|
|
107
|
+
):
|
|
108
|
+
raise ValueError(
|
|
109
|
+
f"display_id_prefix must be 1-16 lowercase letters, "
|
|
110
|
+
f"got: {self.display_id_prefix!r}"
|
|
111
|
+
)
|
|
112
|
+
return self.display_id_prefix
|
|
113
|
+
return getattr(model, "display_id_prefix", None)
|
|
114
|
+
|
|
94
115
|
def get_queryset(self) -> Any:
|
|
95
116
|
"""Get the base queryset.
|
|
96
117
|
|
|
@@ -138,7 +159,7 @@ class DisplayIDLookupMixin:
|
|
|
138
159
|
model=model,
|
|
139
160
|
value=str(value),
|
|
140
161
|
strategies=self._get_strategies(),
|
|
141
|
-
prefix=self.
|
|
162
|
+
prefix=self._get_display_id_prefix(model),
|
|
142
163
|
uuid_field=self._get_uuid_field(),
|
|
143
164
|
slug_field=self._get_slug_field(),
|
|
144
165
|
queryset=queryset,
|
|
@@ -7,7 +7,7 @@ from typing import ClassVar
|
|
|
7
7
|
from django.db import models
|
|
8
8
|
|
|
9
9
|
from .conf import get_setting
|
|
10
|
-
from .encoding import encode_display_id
|
|
10
|
+
from .encoding import PREFIX_PATTERN, encode_display_id
|
|
11
11
|
|
|
12
12
|
__all__ = [
|
|
13
13
|
"DisplayIDMixin",
|
|
@@ -92,6 +92,11 @@ class DisplayIDMixin(models.Model):
|
|
|
92
92
|
if "display_id_prefix" in cls.__dict__:
|
|
93
93
|
prefix = cls.__dict__["display_id_prefix"]
|
|
94
94
|
if prefix is not None:
|
|
95
|
+
if not PREFIX_PATTERN.match(prefix):
|
|
96
|
+
raise ValueError(
|
|
97
|
+
f"{cls.__name__}.display_id_prefix must be 1-16 "
|
|
98
|
+
f"lowercase letters, got: {prefix!r}"
|
|
99
|
+
)
|
|
95
100
|
_register_prefix(prefix, cls.__name__)
|
|
96
101
|
|
|
97
102
|
@classmethod
|
|
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
7
7
|
from django.http import Http404
|
|
8
8
|
|
|
9
9
|
from .conf import get_setting
|
|
10
|
+
from .encoding import PREFIX_PATTERN
|
|
10
11
|
from .exceptions import (
|
|
11
12
|
InvalidIdentifierError,
|
|
12
13
|
LookupError,
|
|
@@ -23,6 +24,8 @@ __all__ = [
|
|
|
23
24
|
"DisplayIDObjectMixin",
|
|
24
25
|
]
|
|
25
26
|
|
|
27
|
+
_NOT_SET: Any = object()
|
|
28
|
+
|
|
26
29
|
|
|
27
30
|
class DisplayIDObjectMixin:
|
|
28
31
|
"""Mixin for Django CBVs that resolves objects by display ID, UUID, or slug.
|
|
@@ -49,7 +52,7 @@ class DisplayIDObjectMixin:
|
|
|
49
52
|
model: type[models.Model] | None = None
|
|
50
53
|
lookup_param: str = "pk"
|
|
51
54
|
lookup_strategies: tuple[StrategyName, ...] | None = None
|
|
52
|
-
display_id_prefix: str | None =
|
|
55
|
+
display_id_prefix: str | None = _NOT_SET
|
|
53
56
|
uuid_field: str | None = None
|
|
54
57
|
slug_field: str | None = None
|
|
55
58
|
|
|
@@ -68,6 +71,26 @@ class DisplayIDObjectMixin:
|
|
|
68
71
|
return self.lookup_strategies
|
|
69
72
|
return get_setting("STRATEGIES") # type: ignore[return-value]
|
|
70
73
|
|
|
74
|
+
def _get_display_id_prefix(self) -> str | None:
|
|
75
|
+
"""Get the display ID prefix.
|
|
76
|
+
|
|
77
|
+
Returns the view's display_id_prefix if set (including None to
|
|
78
|
+
explicitly disable), otherwise falls back to the model's
|
|
79
|
+
display_id_prefix attribute.
|
|
80
|
+
"""
|
|
81
|
+
if self.display_id_prefix is not _NOT_SET:
|
|
82
|
+
if self.display_id_prefix is not None and not PREFIX_PATTERN.match(
|
|
83
|
+
self.display_id_prefix
|
|
84
|
+
):
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"display_id_prefix must be 1-16 lowercase letters, "
|
|
87
|
+
f"got: {self.display_id_prefix!r}"
|
|
88
|
+
)
|
|
89
|
+
return self.display_id_prefix
|
|
90
|
+
if self.model is not None:
|
|
91
|
+
return getattr(self.model, "display_id_prefix", None)
|
|
92
|
+
return None
|
|
93
|
+
|
|
71
94
|
# These may be provided by parent classes
|
|
72
95
|
kwargs: dict[str, Any]
|
|
73
96
|
|
|
@@ -114,7 +137,7 @@ class DisplayIDObjectMixin:
|
|
|
114
137
|
model=self.model,
|
|
115
138
|
value=str(value),
|
|
116
139
|
strategies=self._get_strategies(),
|
|
117
|
-
prefix=self.
|
|
140
|
+
prefix=self._get_display_id_prefix(),
|
|
118
141
|
uuid_field=self._get_uuid_field(),
|
|
119
142
|
slug_field=self._get_slug_field(),
|
|
120
143
|
queryset=qs,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_display_ids-0.1.2 → django_display_ids-0.1.3}/src/django_display_ids/contrib/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|