django-display-ids 0.5.0__py3-none-any.whl → 0.5.1__py3-none-any.whl

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.
@@ -187,6 +187,69 @@ class DisplayIDQuerySet(models.QuerySet[M]):
187
187
  # Execute the query
188
188
  return self.get(**lookup)
189
189
 
190
+ def resolve_identifier(
191
+ self,
192
+ value: str | uuid.UUID,
193
+ *,
194
+ strategies: tuple[StrategyName, ...] | None = None,
195
+ prefix: str | None = None,
196
+ ) -> uuid.UUID:
197
+ """Resolve an identifier to a UUID without fetching the object.
198
+
199
+ For UUID and display_id identifiers, the UUID is extracted by parsing
200
+ alone — no database query is needed. Only slug identifiers require a
201
+ database lookup.
202
+
203
+ This is useful for cursor-based pagination where you need the UUID
204
+ value to build a WHERE clause but don't need the full model instance.
205
+
206
+ Args:
207
+ value: The identifier string (display ID, UUID, or slug),
208
+ or a UUID instance (returned as-is).
209
+ strategies: Strategies to try. Defaults to settings.
210
+ prefix: Expected display ID prefix for validation.
211
+
212
+ Returns:
213
+ The resolved UUID value.
214
+
215
+ Raises:
216
+ Model.DoesNotExist: If the identifier cannot be parsed or
217
+ no matching object exists (slug lookup).
218
+ Model.MultipleObjectsReturned: If multiple objects match (slug).
219
+ """
220
+ model = self.model
221
+ uuid_field = self._get_uuid_field()
222
+
223
+ # UUID objects are returned as-is
224
+ if isinstance(value, uuid.UUID):
225
+ return value
226
+
227
+ slug_field = self._get_slug_field()
228
+ expected_prefix = prefix or self._get_model_prefix()
229
+ lookup_strategies = strategies or self._get_strategies()
230
+
231
+ # Skip slug strategy if the model has no slug field
232
+ if not self._has_slug_field(slug_field):
233
+ lookup_strategies = tuple(s for s in lookup_strategies if s != "slug")
234
+
235
+ # Parse the identifier
236
+ try:
237
+ result = parse_identifier(
238
+ value, lookup_strategies, expected_prefix=expected_prefix
239
+ )
240
+ except DisplayIDLookupError as e:
241
+ raise model.DoesNotExist( # type: ignore[attr-defined]
242
+ f"{model.__name__}: {e}"
243
+ ) from e
244
+
245
+ # UUID and display_id strategies yield a UUID directly — no DB query
246
+ if result.strategy in ("uuid", "display_id"):
247
+ return result.uuid # type: ignore[return-value]
248
+
249
+ # Slug strategy requires a DB lookup
250
+ obj = self.get(**{slug_field: result.slug})
251
+ return getattr(obj, uuid_field) # type: ignore[no-any-return]
252
+
190
253
  def get_by_identifiers(
191
254
  self,
192
255
  values: Sequence[str | uuid.UUID],
@@ -335,6 +398,21 @@ class DisplayIDManager(models.Manager[M]):
335
398
  value, strategies=strategies, prefix=prefix
336
399
  )
337
400
 
401
+ def resolve_identifier(
402
+ self,
403
+ value: str | uuid.UUID,
404
+ *,
405
+ strategies: tuple[StrategyName, ...] | None = None,
406
+ prefix: str | None = None,
407
+ ) -> uuid.UUID:
408
+ """Resolve an identifier to a UUID without fetching the object.
409
+
410
+ See DisplayIDQuerySet.resolve_identifier for details.
411
+ """
412
+ return self.get_queryset().resolve_identifier(
413
+ value, strategies=strategies, prefix=prefix
414
+ )
415
+
338
416
  def get_by_identifiers(
339
417
  self,
340
418
  values: Sequence[str | uuid.UUID],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-display-ids
3
- Version: 0.5.0
3
+ Version: 0.5.1
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: MIT
@@ -11,7 +11,7 @@ django_display_ids/converters.py,sha256=KGD5FYWkuXztO-6TvTtPwMP7xbnAXAaYuk9LvIpx
11
11
  django_display_ids/encoding.py,sha256=csIwUZaQKSOLwRU6-DWGTNGvSxmroyK0Yt7TBCo0AFE,2945
12
12
  django_display_ids/examples.py,sha256=gap5NNPTmE7B5uxiYKoMoK8G-OEtL1Ek0W039l6oJ9I,2689
13
13
  django_display_ids/exceptions.py,sha256=68Kmp9Qdyg3LtzmXfDHIWRuI7MW3M2acZ3C6Wi8zFEw,4489
14
- django_display_ids/managers.py,sha256=tQ1ryAIClAg-mhDp5CgkCEqxld9XVMe6fl-u__DSiOI,11831
14
+ django_display_ids/managers.py,sha256=Oy0uOb2n7OSXXH2yCN2Cec5O2tvYty4cYIzJkmHbj_8,14716
15
15
  django_display_ids/models.py,sha256=_hmgAR4HC3I-5wU2DND6uNLjEllu1Y9eaXeBQ9dWMNI,4313
16
16
  django_display_ids/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  django_display_ids/resolver.py,sha256=blyLo06tIYrYqOA9Ir260tzs9njX1GMAE6ICDJTwfGk,3485
@@ -20,6 +20,6 @@ django_display_ids/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
20
20
  django_display_ids/templatetags/display_ids.py,sha256=4KHE8r8mgSKb7LgIuXJaJB_3UGrzRZvTdLqSCYQtb5I,1157
21
21
  django_display_ids/typing.py,sha256=hxX2QVYtkvFXZBH9ZskbV98N-uOhX_XAMoO-UOBRnEA,568
22
22
  django_display_ids/views.py,sha256=OOhv5G6ake8Siv-yAFFA1s2wOuNng9NYETS1feDygio,4662
23
- django_display_ids-0.5.0.dist-info/WHEEL,sha256=iHtWm8nRfs0VRdCYVXocAWFW8ppjHL-uTJkAdZJKOBM,80
24
- django_display_ids-0.5.0.dist-info/METADATA,sha256=twAX7DSsXtTAbGl5IJbZaJ7MrjndlQV1TVin1nhsLhI,5249
25
- django_display_ids-0.5.0.dist-info/RECORD,,
23
+ django_display_ids-0.5.1.dist-info/WHEEL,sha256=iHtWm8nRfs0VRdCYVXocAWFW8ppjHL-uTJkAdZJKOBM,80
24
+ django_display_ids-0.5.1.dist-info/METADATA,sha256=WImPRXMdSGsx6FU099koONUtetahmJhAV1LVgzNi1jQ,5249
25
+ django_display_ids-0.5.1.dist-info/RECORD,,