django-charid-field icon indicating copy to clipboard operation
django-charid-field copied to clipboard

examples to use other generator?

Open hyusetiawan opened this issue 1 year ago • 10 comments
trafficstars

Is there an example on how to use cuid2 or nanoid? My assumption was passing a function that would return a generated id string would suffice but i keep getting weird errors, for ex: using cuid2:

ValueError: Could not find function cuid in cuid2.generator. ValueError: Cannot serialize: <cuid2.generator.Cuid object at 0x1030071d0> using nanoid: default=nanoid.generate.generate, ^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'function' object has no attribute 'generate'

hyusetiawan avatar Dec 06 '23 03:12 hyusetiawan

Hi @hyusetiawan.

Internally we use it with cuid v1 like this:

from functools import partial
from charidfield import CharIDField
from cuid import cuid as generate_cuid

CuidField = partial(
    CharIDField,
    max_length=40,
    default=generate_cuid,
    help_text=_("A cuid spec public identifier"),
)

And then we import CuidField into a model and use it as we see fit.

generate_cuid is the function which generates the ID string.

So for nanoid (assuming from pypi), it would be:

from functools import partial
from charidfield import CharIDField
from nanoid import generate as generate_nanoid

NanoIDField = partial(
    CharIDField,
    max_length=40,
    default=generate_nanoid,
    help_text=_("A nanoid spec public identifier"),
)

And for cuid2 (again, assuming from pypi), it would be:

from functools import partial
from charidfield import CharIDField
from cuid2 import cuid2_wrapper

cuid2_generator = cuid2_wrapper()


CuidID2Field = partial(
    CharIDField,
    max_length=40,
    default=cuid2_generator,
    help_text=_("A cuid2 spec public identifier"),
)

This is not checked - it's just based on both of their respective documentation.

Let me know how you get on and we can update the docs.

djm avatar Dec 06 '23 10:12 djm

@djm thank you for the thorough response, unfortunately it's still not working for cuid2, here is my code snippet:

from functools import partial
from charidfield import CharIDField
from cuid2 import cuid_wrapper

cuid_generator = cuid_wrapper()

CuidField = partial(
    CharIDField,
    default=cuid_generator,
    max_length=40,  # type: ignore
    unique=True,
    help_text="global id.",
)

here is the error: ValueError: Could not find function cuid in cuid2.generator.

note: it's cuid_wrapper not cuid2_wrapper, at least for the latest cuid2 i installed

hyusetiawan avatar Dec 08 '23 20:12 hyusetiawan

@djm bump + happy new year :D

hyusetiawan avatar Jan 03 '24 04:01 hyusetiawan

I'm also running into this

ezarowny avatar Jan 31 '24 17:01 ezarowny

One workaround, for the moment, is to use the "direct instantiation" approach:


from functools import partial

from charidfield import CharIDField
from cuid2 import Cuid
from django.utils.translation import gettext_lazy as _

CUID_GENERATOR: Cuid = Cuid()

CuidField = partial(
    CharIDField,
    default=CUID_GENERATOR.generate,
    max_length=40,
    help_text=_("cuid2-format identifier for this entity."),
)

ezarowny avatar Jan 31 '24 17:01 ezarowny

The migration doesn't seem to be using the local generator though:

    migrations.AddField(
            model_name="smartgoal",
            name="public_id",
            field=charidfield.fields.CharIDField(
                default=cuid2.generator.Cuid.generate,
                help_text="cuid2-format identifier for this entity.",
                max_length=40,
                prefix="sg_",
                unique=True,
            ),
        ),

ezarowny avatar Jan 31 '24 17:01 ezarowny

Well, that doesn't work. Back to the drawing board!

ezarowny avatar Jan 31 '24 17:01 ezarowny

from functools import partial

from charidfield import CharIDField
from cuid2 import Cuid

cuid_generator = Cuid()

def generate_cuid():
    return cuid_generator.generate()

CUIDField = partial(
    CharIDField,
    default=generate_cuid,
    max_length=40,
    help_text="CUID field",
    editable=False,
    verbose_name="CUID",
)

thats how it works

ReDev1L avatar Jan 20 '25 16:01 ReDev1L

@ReDev1L what happens if you add that field that to a model with existing rows?

ezarowny avatar Jan 20 '25 16:01 ezarowny

You would need to add it as nullable, back-populate, and then make the field non-null after. This is (unfortunately) the standard way to add a no-downtime column to any populated table, it is a bit of a faff but it gets the job done.

So you could have that CUIDField partial defined as they did, and then:

class SomeModel(models.Model):

    a_cuid2_field = CUIDField(null=True)

Then create migration and release.

Back-populate via a method of your choosing (we do it with a management command).

Then remove the null=True and create another migration.

Release that, and then you're in the new world.

Remember, all the partial is doing is supplying some defaults - you can still override them by passing new params in :)


Sorry for missing the original replies on this thread, we have been a tad busy.

djm avatar Jan 20 '25 19:01 djm