Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default value generating a UUID breaks migrations in django 1.7, is there a workaround?

Django 1.7 now requires that migrations be setup. Unfortunately, using lambdas or similar in default field values breaks this process.

I have the following in a model:

def make_uuid(type):
    """Takes an entity type identifier string as input and returns a hex of UUID2 with a 
    type identifier pre-pended for readability"""

    return str(type)+str(uuid.uuid1().hex)

class Accounts(models.Model):
    """Model representing Accounts"""

    PENDING_STATUS = 0
    ACTIVE_STATUS = 1
    SUSPENDED_STATUS = 2
    CANCELLED_STATUS = 3
    BETA_STATUS = 4

    STATUS_CHOICES = (
        (PENDING_STATUS, 'Pending'),
        (ACTIVE_STATUS, 'Active'),
        (SUSPENDED_STATUS, 'Suspended'),
        (CANCELLED_STATUS, 'Cancelled'),
        (BETA_STATUS, 'Beta'),
    )

    account_name = models.CharField(max_length=255)
    account_uuid = models.CharField(max_length=34, default=partial(make_uuid,'AC'), db_index=True, unique=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    updated_by = models.ForeignKey(User, null=True, blank=True)
    status = models.IntegerField(max_length=2, choices=STATUS_CHOICES, default=PENDING_STATUS)

The call to partial breaks the migration process with the following error:

ValueError: Cannot serialize: <functools.partial object at 0x10e5cf9f0>
There are some values Django cannot serialize into migration files.

I still need to auto-generate the UUID, so does anyone know of a workaround to this that doesn't break migrations?

like image 672
Sologoub Avatar asked Feb 11 '23 20:02

Sologoub


1 Answers

The issue here is that the migrations system needs to serialize the function definition, and isn't able to do so with the dynamically-created object returned by partial().

(Note that as of version 1.9 Django is in fact able to serialize partial() callables, and the code above would work.)

To fix this use a module-level function instead:

def make_uuid_ac():
    return make_uuid('AC')

class Accounts(models.Model):
    ....
    account_uuid = models.CharField(..., default=make_uuid_ac)
like image 161
Kevin Christopher Henry Avatar answered Feb 18 '23 21:02

Kevin Christopher Henry