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