Shunted the responsibility in Entity proxy models for setting an Attribute's value...
authorStephen Burrows <stephen.r.burrows@gmail.com>
Thu, 14 Oct 2010 20:24:59 +0000 (16:24 -0400)
committerStephen Burrows <stephen.r.burrows@gmail.com>
Thu, 14 Oct 2010 20:24:59 +0000 (16:24 -0400)
models/base.py
models/fields.py

index 5d9d761..23cccb6 100644 (file)
@@ -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()
        
index 0c68858..0c31026 100644 (file)
@@ -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):