1 from django.db import models
2 from django.db.models import signals
3 from django.core.exceptions import ObjectDoesNotExist, FieldError
4 from django.contrib.contenttypes.models import ContentType
5 from functools import partial
6 from philo.models.base import Attribute, Relationship, Entity
9 __all__ = ('AttributeField', 'RelationshipField')
12 class AttributeFieldDescriptor(object):
13 def __init__(self, field):
16 def __get__(self, instance, owner):
19 return instance.attribute_set.get(key__exact=self.field.key).value
20 except ObjectDoesNotExist:
23 raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__))
25 def __set__(self, instance, value):
27 attribute = instance.attribute_set.get(key__exact=self.field.key)
28 except ObjectDoesNotExist:
29 attribute = Attribute()
30 attribute.entity = instance
31 attribute.key = self.field.key
32 attribute.value = value
35 def __delete__(self, instance):
36 instance.attribute_set.filter(key__exact=self.field.key).delete()
39 class AttributeField(object):
40 def __init__(self, key):
43 def actually_contribute_to_class(self, sender, **kwargs):
44 setattr(sender, self.name, AttributeFieldDescriptor(self))
46 def contribute_to_class(self, cls, name):
47 if issubclass(cls, Entity):
49 signals.class_prepared.connect(self.actually_contribute_to_class, sender=cls)
51 raise FieldError('AttributeFields can only be declared on Entity subclasses.')
54 class RelationshipFieldDescriptor(object):
55 def __init__(self, field):
58 def __get__(self, instance, owner):
61 return instance.relationship_set.get(key__exact=self.field.key).value
62 except ObjectDoesNotExist:
65 raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__))
67 def __set__(self, instance, value):
68 if isinstance(value, (models.Model, type(None))):
70 relationship = instance.relationship_set.get(key__exact=self.field.key)
71 except ObjectDoesNotExist:
72 relationship = Relationship()
73 relationship.entity = instance
74 relationship.key = self.field.key
75 relationship.value = value
78 raise AttributeError('The \'%\' attribute can only be set using existing Model objects.' % self.field.name)
80 def __delete__(self, instance):
81 instance.relationship_set.filter(key__exact=self.field.key).delete()
84 class RelationshipField(object):
85 def __init__(self, key):
88 def actually_contribute_to_class(self, sender, **kwargs):
89 setattr(sender, self.name, RelationshipFieldDescriptor(self))
91 def contribute_to_class(self, cls, name):
92 if issubclass(cls, Entity):
94 signals.class_prepared.connect(self.actually_contribute_to_class, sender=cls)
96 raise FieldError('RelationshipFields can only be declared on Entity subclasses.')