From: Joseph Spiros Date: Sat, 31 Jul 2010 03:16:52 +0000 (-0400) Subject: Initial implementation of AttributeField and RelationshipField. X-Git-Tag: philo-0.9~45^2~2 X-Git-Url: http://git.ithinksw.org/philo.git/commitdiff_plain/2f2aed7e371d11b021432124de8f9bdd436b0832 Initial implementation of AttributeField and RelationshipField. These objects are not actual Fields, but rather they simply add descriptors to Entity subclasses which provide transparent access to specific attributes and relationships. --- diff --git a/models/__init__.py b/models/__init__.py index b9ea3ac..5d39ac6 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -2,6 +2,7 @@ from philo.models.base import * from philo.models.collections import * from philo.models.nodes import * from philo.models.pages import * +from philo.models.fields import * from django.contrib.auth.models import User, Group from django.contrib.sites.models import Site diff --git a/models/fields.py b/models/fields.py new file mode 100644 index 0000000..7f76b9c --- /dev/null +++ b/models/fields.py @@ -0,0 +1,96 @@ +from django.db import models +from django.db.models import signals +from django.core.exceptions import ObjectDoesNotExist, FieldError +from django.contrib.contenttypes.models import ContentType +from functools import partial +from philo.models.base import Attribute, Relationship, Entity + + +__all__ = ('AttributeField', 'RelationshipField') + + +class AttributeFieldDescriptor(object): + def __init__(self, field): + self.field = field + + def __get__(self, instance, owner): + if instance: + try: + return instance.attribute_set.get(key__exact=self.field.key).value + except ObjectDoesNotExist: + return None + else: + raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__)) + + def __set__(self, instance, value): + try: + attribute = instance.attribute_set.get(key__exact=self.field.key) + except ObjectDoesNotExist: + attribute = Attribute() + attribute.entity = instance + attribute.key = self.field.key + attribute.value = value + attribute.save() + + def __delete__(self, instance): + instance.attribute_set.filter(key__exact=self.field.key).delete() + + +class AttributeField(object): + def __init__(self, key): + self.key = key + + def actually_contribute_to_class(self, sender, **kwargs): + setattr(sender, self.name, AttributeFieldDescriptor(self)) + + def contribute_to_class(self, cls, name): + if issubclass(cls, Entity): + self.name = name + signals.class_prepared.connect(self.actually_contribute_to_class, sender=cls) + else: + raise FieldError('AttributeFields can only be declared on Entity subclasses.') + + +class RelationshipFieldDescriptor(object): + def __init__(self, field): + self.field = field + + def __get__(self, instance, owner): + if instance: + try: + return instance.relationship_set.get(key__exact=self.field.key).value + except ObjectDoesNotExist: + return None + else: + raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__)) + + def __set__(self, instance, value): + if isinstance(value, (models.Model, type(None))): + try: + relationship = instance.relationship_set.get(key__exact=self.field.key) + except ObjectDoesNotExist: + relationship = Relationship() + relationship.entity = instance + relationship.key = self.field.key + relationship.value = value + relationship.save() + else: + raise AttributeError('The \'%\' attribute can only be set using existing Model objects.' % self.field.name) + + def __delete__(self, instance): + instance.relationship_set.filter(key__exact=self.field.key).delete() + + +class RelationshipField(object): + def __init__(self, key): + self.key = key + + def actually_contribute_to_class(self, sender, **kwargs): + setattr(sender, self.name, RelationshipFieldDescriptor(self)) + + def contribute_to_class(self, cls, name): + if issubclass(cls, Entity): + self.name = name + signals.class_prepared.connect(self.actually_contribute_to_class, sender=cls) + else: + raise FieldError('RelationshipFields can only be declared on Entity subclasses.') \ No newline at end of file