Search code examples
pythondjangodjango-modelslambdadatabase-migration

UUID as pk in Django overwriting models


Here is the deal. It worked, when done this way:

class UUIDField(CharField):

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = kwargs.get('max_length', 22 )
        # kwargs['blank'] = True
        kwargs['default'] = lambda: uuid.uuid1().bytes.encode('base64').rstrip('=\n').replace('/', '_')
        CharField.__init__(self, *args, **kwargs)

class UUIDModel(models.Model):

    uuid = UUIDField(primary_key=True, max_length=22, editable=False)

Well as you may understand, the rest of the models inherit UUIDModel and everyone lives happily ever after. The problem is, that the built in Django migrations facilities (and South for that matter) don't go well with lambdas. Here is my take on trying to work around the lambda:

class UUIDField(CharField):

    def _gen_uuid(self):
      return uuid.uuid1().bytes.encode('base64').rstrip('=\n').replace('/', '_')

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = kwargs.get('max_length', 22 )
        # kwargs['blank'] = True
        kwargs['default'] = self._gen_uuid()
        CharField.__init__(self, *args, **kwargs)

Seems legit, but now the models get overwritten, that is the UUID doesn't change and every new model gets written to the same pk. As result I can't create more than one instance of anything. Where I've gone wrong? What the lambda does, my code does not? And most importantly, how it could be fixed?


Solution

  • The comment by @pavel_form helped me to understand the root of my problem. Passing over the callable seems to have fixed that:

    class UUIDField(CharField):
    
        def _gen_uuid(self):
          return uuid.uuid1().bytes.encode('base64').rstrip('=\n').replace('/', '_')
    
        def __init__(self, *args, **kwargs):
            kwargs['max_length'] = kwargs.get('max_length', 22 )
            # kwargs['blank'] = True
            kwargs['default'] = self._gen_uuid
            CharField.__init__(self, *args, **kwargs)
    

    It still causes fair share of problems with the migrations, though. South migrate error: name 'UUID' is not defined (suggested by @pavel-form) takes it even further, omitting definition of the special UUIDFIeld and it is believed to be working well with migrations. I'd be looking in that direction.