From 5a45551fd535081084355dba85642ada72b71750 Mon Sep 17 00:00:00 2001 From: Stephen Burrows Date: Thu, 14 Oct 2010 16:24:59 -0400 Subject: [PATCH] Shunted the responsibility in Entity proxy models for setting an Attribute's value onto the field that manages the model's relationship to that attribute. --- models/base.py | 40 ++++++++------------------ models/fields.py | 75 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 68 insertions(+), 47 deletions(-) diff --git a/models/base.py b/models/base.py index 5d9d761..23cccb6 100644 --- a/models/base.py +++ b/models/base.py @@ -104,6 +104,7 @@ class ForeignKeyValue(AttributeValue): class ManyToManyValue(AttributeValue): + # TODO: Change object_ids to object_pks. content_type = models.ForeignKey(ContentType, related_name='many_to_many_value_set', limit_choices_to=value_content_type_limiter, verbose_name='Value type', null=True, blank=True) object_ids = models.CommaSeparatedIntegerField(max_length=300, verbose_name='Value IDs', null=True, blank=True) @@ -137,7 +138,12 @@ class ManyToManyValue(AttributeValue): return form_class(self.content_type.model_class()._default_manager.all(), **kwargs) def apply_data(self, cleaned_data): - self.value = cleaned_data.get('value', None) + if 'value' in cleaned_data and cleaned_data['value'] is not None: + self.value = cleaned_data['value'] + else: + self.content_type = cleaned_data.get('content_type', None) + # If there is no value set in the cleaned data, clear the stored value. + self.object_ids = "" class Meta: app_label = 'philo' @@ -154,29 +160,6 @@ class Attribute(models.Model): key = models.CharField(max_length=255) - def get_value_class(self, value): - if isinstance(value, models.query.QuerySet): - return ManyToManyValue - elif isinstance(value, models.Model) or (value is None and self.value_content_type.model_class() is ForeignKeyValue): - return ForeignKeyValue - else: - return JSONValue - - def set_value(self, value): - # is this useful? The best way of doing it? - value_class = self.get_value_class(value) - - if self.value is None or value_class != self.value_content_type.model_class(): - if self.value is not None: - self.value.delete() - new_value = value_class() - new_value.value = value - new_value.save() - self.value = new_value - else: - self.value.value = value - self.value.save() - def __unicode__(self): return u'"%s": %s' % (self.key, self.value) @@ -254,14 +237,15 @@ class Entity(models.Model): self.attribute_set.filter(key__exact=key).delete() del self._removed_attribute_registry[:] - for key, value in self._added_attribute_registry.items(): + for field, value in self._added_attribute_registry.items(): try: - attribute = self.attribute_set.get(key__exact=key) + attribute = self.attribute_set.get(key__exact=field.key) except Attribute.DoesNotExist: attribute = Attribute() attribute.entity = self - attribute.key = key - attribute.set_value(value) + attribute.key = field.key + + field.set_attribute_value(attribute, value) attribute.save() self._added_attribute_registry.clear() diff --git a/models/fields.py b/models/fields.py index 0c68858..0c31026 100644 --- a/models/fields.py +++ b/models/fields.py @@ -47,9 +47,9 @@ 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: + if self.field in instance._added_attribute_registry: + return instance._added_attribute_registry[self.field] + if self.field in instance._removed_attribute_registry: return None try: return instance.attributes[self.field.key] @@ -62,24 +62,24 @@ class AttributeFieldDescriptor(object): raise NotImplementedError('AttributeFieldDescriptor subclasses must implement a __set__ method.') def __delete__(self, instance): - 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) + if self.field in instance._added_attribute_registry: + del instance._added_attribute_registry[self.field] + instance._removed_attribute_registry.append(self.field) class JSONAttributeDescriptor(AttributeFieldDescriptor): def __set__(self, instance, value): - 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 + if self.field in instance._removed_attribute_registry: + instance._removed_attribute_registry.remove(self.field) + instance._added_attribute_registry[self.field] = value class ForeignKeyAttributeDescriptor(AttributeFieldDescriptor): def __set__(self, instance, value): if isinstance(value, (models.Model, type(None))): - 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 + if self.field in instance._removed_attribute_registry: + instance._removed_attribute_registry.remove(self.field) + instance._added_attribute_registry[self.field] = value else: raise AttributeError('The \'%s\' attribute can only be set using existing Model objects.' % self.field.name) @@ -87,9 +87,9 @@ class ForeignKeyAttributeDescriptor(AttributeFieldDescriptor): class ManyToManyAttributeDescriptor(AttributeFieldDescriptor): def __set__(self, instance, value): if isinstance(value, models.QuerySet): - 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 + if self.field in instance._removed_attribute_registry: + instance._removed_attribute_registry.remove(self.field) + instance._added_attribute_registry[self.field] = value else: raise AttributeError('The \'%s\' attribute can only be set to a QuerySet.' % self.field.name) @@ -99,6 +99,17 @@ class AttributeField(EntityProxyField): super(AttributeField, self).contribute_to_class(cls, name) if self.key is None: self.key = name + + def set_attribute_value(self, attribute, value, value_class): + if not isinstance(attribute.value, value_class): + if isinstance(attribute.value, models.Model): + attribute.value.delete() + new_value = value_class() + else: + new_value = attribute.value + new_value.value = value + new_value.save() + attribute.value = new_value class JSONAttribute(AttributeField): @@ -117,7 +128,16 @@ class JSONAttribute(AttributeField): return self.field_template.formfield(**defaults) def value_from_object(self, obj): - return getattr(obj, self.attname).value + try: + return getattr(obj, self.attname).value + except AttributeError: + return None + + def set_attribute_value(self, attribute, value, value_class=None): + if value_class is None: + from philo.models.base import JSONValue + value_class = JSONValue + super(JSONAttribute, self).set_attribute_value(attribute, value, value_class) class ForeignKeyAttribute(AttributeField): @@ -137,13 +157,30 @@ class ForeignKeyAttribute(AttributeField): return form_class(self.model._default_manager.complex_filter(self.limit_choices_to), **defaults) def value_from_object(self, obj): - relobj = super(ForeignKeyAttribute, self).value_from_object(obj).value + try: + relobj = super(ForeignKeyAttribute, self).value_from_object(obj).value + except AttributeError: + return None return getattr(relobj, 'pk', None) + + def set_attribute_value(self, attribute, value, value_class=None): + if value_class is None: + from philo.models.base import ForeignKeyValue + value_class = ForeignKeyValue + super(ForeignKeyAttribute, self).set_attribute_value(attribute, value, value_class) -class ManyToManyAttribute(AttributeField): +class ManyToManyAttribute(ForeignKeyAttribute): descriptor_class = ManyToManyAttributeDescriptor - #FIXME: Add __init__ and formfield methods + + def formfield(self, form_class=forms.ModelMultipleChoiceField, **kwargs): + return super(ManyToManyAttribute, self).formfield(form_class, **kwargs) + + def set_attribute_value(self, attribute, value, value_class=None): + if value_class is None: + from philo.models.base import ManyToManyValue + value_class = ManyToManyValue + super(ManyToManyAttribute, self).set_attribute_value(attribute, value, value_class) class TemplateField(models.TextField): -- 2.20.1