#Using non-standard UUID classes with the ORM

13 messages · Page 1 of 1 (latest)

pseudo yarrow
#

Hey all, I was doing some experimentation with UUID7. I liked it so far and started using it in two different projects.

I found this library for rust-based UUID implementation and it seems to be working relatively fast:

But I can't use it as a field default. When I define a model like this

from uuid_utils import uuid7

class UUIDModel(models.Model):
    id = models.UUIDField(
        default=uuid7,
        editable=False,
        primary_key=True,
        verbose_name="ID",
    )

    class Meta:
        abstract = True

make and apply migrations works fine, but then model creation fails with

ValidationError: ['“0190c9d9-455d-7a41-8f69-910dbb580112” is not a valid UUID.']

which kind of misleading because it's a valid UUID, just not the UUID type Django excepts.

I tried to dive deeper and wrote new validations, but then there were other issues converting non standard UUID class to something db understands.

My question is, is there a quick solution here? Is there some sort of registry that I could say "This is a valid UUID type too, use it as same as the other"?

GitHub

Python bindings to Rust UUID. Contribute to aminalaee/uuid-utils development by creating an account on GitHub.

Gist

Compare UUID7 generation speed of different packages - uuid7_generation_speed.py

small pebble
#

Looking at the source for UUIDField I think you would have to replace all instances of Python's uuid with something 3rd party. Or wait until this PR get's pushed through and there is a new release: https://github.com/python/cpython/pull/121119

GitHub

Based on the discussion in #89083 and https://discuss.python.org/t/rfc-4122-9562-uuid-version-7-and-8-implementation/56725/2, this is the implementation that I suggest for the standard library.
The...

pseudo yarrow
#

@small pebble I got another package working just fine with the Python's native UUID and UUID7, I was just looking for this specific case

small pebble
# pseudo yarrow <@441456707596713985> I got another package working just fine with the Python's ...

Can you share a bit more of the stack trace? Looking at Django I believe this is where the error is coming from:

    def to_python(self, value):
        if value is not None and not isinstance(value, uuid.UUID):
            input_form = "int" if isinstance(value, int) else "hex"
            try:
                return uuid.UUID(**{input_form: value})
            except (AttributeError, ValueError):
                raise exceptions.ValidationError(
                    self.error_messages["invalid"],
                    code="invalid",
                    params={"value": value},
                )
        return value

https://github.com/django/django/blob/main/django/db/models/fields/__init__.py#L2761C1-L2772C21

#

Here's a minimal reproducible example:

import uuid
from uuid_utils import uuid7

def to_python(value):
    if value is not None and not isinstance(value, uuid.UUID):
        input_form = "int" if isinstance(value, int) else "hex"
        try:
            return uuid.UUID(**{input_form: value})
        except (AttributeError, ValueError) as e:
            raise Exception from e
    return value

new_uuid = uuid7()
py_uuid = to_python(new_uuid)
#

How did you get the Python built-in library to work with UUID v7?

small pebble
# small pebble Here's a minimal reproducible example: ```python import uuid from uuid_utils im...

And here's the output of this code btw:

Traceback (most recent call last):
  File "<stdin>", line 5, in to_python
  File "C:\Users\jonathan.biemond\AppData\Local\Programs\Python\Python310\lib\uuid.py", line 174, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
AttributeError: 'uuid_utils.UUID' object has no attribute 'replace'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in to_python
Exception
pseudo yarrow
#

@small pebble Yea, I passed this one by just copying the code and replacing the UUID class

#

then at a lower level, pyscopg doesn't recognize it as a valid uuid but I don'T have the stacktrace for it rn

small pebble
#

Okay, looking at it closer I see uuid.UUID() expects a string as an input. What if you just pass a string instead of uuid_utils.UUID?

#

Something like this:

from uuid_utils import uuid7

def uuid7_str():
    return str(uuid7())

class UUIDModel(models.Model):
    id = models.UUIDField(
        default=uuid7_str,
        editable=False,
        primary_key=True,
        verbose_name="ID",
    )

    class Meta:
        abstract = True
pseudo yarrow
#

@small pebble The point was to stay away from that, string conversion works but it involves python native UUID, which has the init time cost