from django.db import models from uuid import uuid4 import types class GUIDField(models.CharField): """ A ModelField to store a GUID """ def __init__(self, *args, **kwargs): kwargs['max_length'] = kwargs.get('max_length', 64 ) kwargs['unique'] = kwargs.get('unique', True ) kwargs['editable'] = kwargs.get('editable', False ) kwargs['blank'] = kwargs.get('blank', False ) super(GUIDField, self).__init__(*args, **kwargs) def contribute_to_class(self,cls,name): """ called when a GUIDField is added to a class this inserts the "getGUID" fn to that class it also registers a callback w/ the cls post_init signal (so that I can give it a unique value then) """ def _getGUID(self): return self._guid cls.getGUID = types.MethodType(_getGUID,None,cls) # connect cls 'post_init' signal to the setValue() method post_init.connect(self.setValue,cls) super(GUIDField,self).contribute_to_class(cls,name) def setValue(self,*args,**kwargs): """ actually sets the GUID value """ instance = kwargs.get("instance",None) if instance: if not instance._guid: # only set the GUID if it hasn't already been set by __init__ instance._guid = str(uuid4()) def guid(): """ decorator that specifies that a model has a _guid element, which can be accessed using the getGUID() method. """ def decorator(obj): # create the field guid_field = GUIDField(default=str(uuid4())) # add it to the object guid_field.contribute_to_class(obj, "_guid") # return the modified object return obj return decorator