class ImportObject(models.Model):
    u'''
    Base class to import model *instance* specific code at runtime.

    By default the model instance contains a python import string (myapp.foo.MyClass)
    in the primary key.

    Example:
        my_workflow=WorkflowDefinition.objects.get(pk='myapp.foo.MyClass')
        my_workflow.object --> instance of myapp.foo.MyClass

    myapp.foo.MyClass can be a normal Python class or a Model subclass.

    If myapp.foo.MyClass is a subclass of Model. It should have a
    OneToOneField to (in this example) WorkflowDefinition.

    Why not use content types and generic relations which are provided
    by django?  The imported class don't need to be a model. It can be
    plain python class.  Next argument: because it does not use serial
    (auto increment) primary keys.  Explicit primary keys don't clash
    if you want to deploy applications in several projects.

    '''
    class Meta:
        abstract=True
    _import_object_attribute='pk'
    _cls=None
    @property
    def cls(self):
        if not self._cls is None:
            return self._cls
        import_string=getattr(self, self._import_object_attribute)
        if not import_string:
            cls=None
        else:
            if isinstance(import_string, models.Model):
                import_string=import_string.pk # myapp.foo.MyClass
            cls=import_from_string(import_string)
        
        self._cls=cls
        return cls

    _object=None
    @property
    def object(self):
        if not self._object is None:
            return self._object
        cls=self.cls
        if cls is None:
            obj=None
        else:
            if issubclass(cls, models.Model):
                obj=self.cls.objects.get(pk=self)
            else:
                obj=self.cls(self)

        self._object=obj
        return obj

def import_from_string(to_import):
    u'''
    Import a object (variable, method, class ...) with a string.
    Example: 'myapp.models.FooModel'
    '''
    if not '.' in to_import:
        raise ImportError('No "." in %r' % to_import)
    idx=to_import.rindex('.')
    module_name=to_import[:idx]
    attr=to_import[idx+1:]
    module=__import__(module_name, {}, {}, [attr])
    something=getattr(module, attr, None)
    if not something:
        raise ImportError('module %s has no attribute %r' % (module_name, attr))
    return something