ImportObject: Import model *instance* specific code at runtime

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
                                                              

More like this

  1. . by jeremydw 3 years, 8 months ago
  2. madslug by catellar 2 years, 7 months ago
  3. watermark by dingdongquan 3 years, 3 months ago
  4. convert youtube url for iframe, js api by ivanff 1 year ago
  5. default url routing and shortcut by vicalloy 4 years, 10 months ago

Comments

(Forgotten your password?)