AttributeFields and RelationshipFields now store their changes and do not commit...
[philo.git] / models / fields.py
1 from django.db import models
2 from django.db.models import signals
3 from django.core.exceptions import FieldError
4 from philo.models.base import Entity
5
6
7 __all__ = ('AttributeField', 'RelationshipField')
8
9
10 class AttributeFieldDescriptor(object):
11         def __init__(self, field):
12                 self.field = field
13         
14         def __get__(self, instance, owner):
15                 if instance:
16                         if self.field.key in instance._added_attribute_registry:
17                                 return instance._added_attribute_registry[self.field.key]
18                         if self.field.key in instance._removed_attribute_registry:
19                                 return None
20                         try:
21                                 return instance.attributes[self.field.key]
22                         except KeyError:
23                                 return None
24                 else:
25                         raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__))
26         
27         def __set__(self, instance, value):
28                 if self.field.key in instance._removed_attribute_registry:
29                         instance._removed_attribute_registry.remove(self.field.key)
30                 instance._added_attribute_registry[self.field.key] = value
31         
32         def __delete__(self, instance):
33                 if self.field.key in instance._added_attribute_registry:
34                         del instance._added_attribute_registry[self.field.key]
35                 instance._removed_attribute_registry.append(self.field.key)
36
37
38 class AttributeField(object):
39         def __init__(self, key):
40                 self.key = key
41         
42         def actually_contribute_to_class(self, sender, **kwargs):
43                 setattr(sender, self.name, AttributeFieldDescriptor(self))
44         
45         def contribute_to_class(self, cls, name):
46                 if issubclass(cls, Entity):
47                         self.name = name
48                         signals.class_prepared.connect(self.actually_contribute_to_class, sender=cls)
49                 else:
50                         raise FieldError('AttributeFields can only be declared on Entity subclasses.')
51
52
53 class RelationshipFieldDescriptor(object):
54         def __init__(self, field):
55                 self.field = field
56         
57         def __get__(self, instance, owner):
58                 if instance:
59                         if self.field.key in instance._added_relationship_registry:
60                                 return instance._added_relationship_registry[self.field.key]
61                         if self.field.key in instance._removed_relationship_registry:
62                                 return None
63                         try:
64                                 return instance.relationships[self.field.key]
65                         except KeyError:
66                                 return None
67                 else:
68                         raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__))
69         
70         def __set__(self, instance, value):
71                 if isinstance(value, (models.Model, type(None))):
72                         if self.field.key in instance._removed_relationship_registry:
73                                 instance._removed_relationship_registry.remove(self.field.key)
74                         instance._added_relationship_registry[self.field.key] = value
75                 else:
76                         raise AttributeError('The \'%s\' attribute can only be set using existing Model objects.' % self.field.name)
77         
78         def __delete__(self, instance):
79                 if self.field.key in instance._added_relationship_registry:
80                         del instance._added_relationship_registry[self.field.key]
81                 instance._removed_relationship_registry.append(self.field.key)
82
83
84 class RelationshipField(object):
85         def __init__(self, key):
86                 self.key = key
87         
88         def actually_contribute_to_class(self, sender, **kwargs):
89                 setattr(sender, self.name, RelationshipFieldDescriptor(self))
90         
91         def contribute_to_class(self, cls, name):
92                 if issubclass(cls, Entity):
93                         self.name = name
94                         signals.class_prepared.connect(self.actually_contribute_to_class, sender=cls)
95                 else:
96                         raise FieldError('RelationshipFields can only be declared on Entity subclasses.')