From 2f2aed7e371d11b021432124de8f9bdd436b0832 Mon Sep 17 00:00:00 2001 From: Joseph Spiros Date: Fri, 30 Jul 2010 23:16:52 -0400 Subject: [PATCH] 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. --- models/__init__.py | 1 + models/fields.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 models/fields.py 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 -- 2.20.1