From aca27b0d4429d193b539f993eb629d28efd2157b Mon Sep 17 00:00:00 2001 From: Joseph Spiros Date: Sun, 1 Aug 2010 04:55:42 -0400 Subject: [PATCH] AttributeFields and RelationshipFields now store their changes and do not commit them until their model has been saved. --- models/base.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ models/fields.py | 54 ++++++++++++++++++++++----------------------- 2 files changed, 84 insertions(+), 27 deletions(-) diff --git a/models/base.py b/models/base.py index 6f23191..37710b8 100644 --- a/models/base.py +++ b/models/base.py @@ -114,6 +114,63 @@ class Entity(models.Model): def relationships(self): return QuerySetMapper(self.relationship_set) + @property + def _added_attribute_registry(self): + if not hasattr(self, '_real_added_attribute_registry'): + self._real_added_attribute_registry = {} + return self._real_added_attribute_registry + + @property + def _removed_attribute_registry(self): + if not hasattr(self, '_real_removed_attribute_registry'): + self._real_removed_attribute_registry = [] + return self._real_removed_attribute_registry + + @property + def _added_relationship_registry(self): + if not hasattr(self, '_real_added_relationship_registry'): + self._real_added_relationship_registry = {} + return self._real_added_relationship_registry + + @property + def _removed_relationship_registry(self): + if not hasattr(self, '_real_removed_relationship_registry'): + self._real_removed_relationship_registry = [] + return self._real_removed_relationship_registry + + def save(self, *args, **kwargs): + super(Entity, self).save(*args, **kwargs) + + for key in self._removed_attribute_registry: + self.attribute_set.filter(key__exact=key).delete() + del self._removed_attribute_registry[:] + + for key, value in self._added_attribute_registry.items(): + try: + attribute = self.attribute_set.get(key__exact=key) + except Attribute.DoesNotExist: + attribute = Attribute() + attribute.entity = self + attribute.key = key + attribute.value = value + attribute.save() + self._added_attribute_registry.clear() + + for key in self._removed_relationship_registry: + self.relationship_set.filter(key__exact=key).delete() + del self._removed_relationship_registry[:] + + for key, value in self._added_relationship_registry.items(): + try: + relationship = self.relationship_set.get(key__exact=key) + except Relationship.DoesNotExist: + relationship = Relationship() + relationship.entity = self + relationship.key = key + relationship.value = value + relationship.save() + self._added_relationship_registry.clear() + class Meta: abstract = True diff --git a/models/fields.py b/models/fields.py index 7f76b9c..467befb 100644 --- a/models/fields.py +++ b/models/fields.py @@ -1,9 +1,7 @@ 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 +from django.core.exceptions import FieldError +from philo.models.base import Entity __all__ = ('AttributeField', 'RelationshipField') @@ -15,25 +13,26 @@ class AttributeFieldDescriptor(object): def __get__(self, instance, owner): if instance: + if self.field.key in instance._added_attribute_registry: + return instance._added_attribute_registry[self.field.key] + if self.field.key in instance._removed_attribute_registry: + return None try: - return instance.attribute_set.get(key__exact=self.field.key).value - except ObjectDoesNotExist: + return instance.attributes[self.field.key] + except KeyError: 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() + if self.field.key in instance._removed_attribute_registry: + instance._removed_attribute_registry.remove(self.field.key) + instance._added_attribute_registry[self.field.key] = value def __delete__(self, instance): - instance.attribute_set.filter(key__exact=self.field.key).delete() + if self.field.key in instance._added_attribute_registry: + del instance._added_attribute_registry[self.field.key] + instance._removed_attribute_registry.append(self.field.key) class AttributeField(object): @@ -57,28 +56,29 @@ class RelationshipFieldDescriptor(object): def __get__(self, instance, owner): if instance: + if self.field.key in instance._added_relationship_registry: + return instance._added_relationship_registry[self.field.key] + if self.field.key in instance._removed_relationship_registry: + return None try: - return instance.relationship_set.get(key__exact=self.field.key).value - except ObjectDoesNotExist: + return instance.relationships[self.field.key] + except KeyError: 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() + if self.field.key in instance._removed_relationship_registry: + instance._removed_relationship_registry.remove(self.field.key) + instance._added_relationship_registry[self.field.key] = value else: - raise AttributeError('The \'%\' attribute can only be set using existing Model objects.' % self.field.name) + raise AttributeError('The \'%s\' 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() + if self.field.key in instance._added_relationship_registry: + del instance._added_relationship_registry[self.field.key] + instance._removed_relationship_registry.append(self.field.key) class RelationshipField(object): -- 2.20.1