Split forms into containers, entities, and fields. Split attribute fields out from...
[philo.git] / models / base.py
index 8140520..20693b7 100644 (file)
@@ -56,10 +56,15 @@ class AttributeValue(models.Model):
        def attribute(self):
                return self.attribute_set.all()[0]
        
        def attribute(self):
                return self.attribute_set.all()[0]
        
-       def apply_data(self, data):
+       def set_value(self, value):
+               raise NotImplementedError
+       
+       def value_formfields(self, **kwargs):
+               """Define any formfields that would be used to construct an instance of this value."""
                raise NotImplementedError
        
                raise NotImplementedError
        
-       def value_formfield(self, **kwargs):
+       def construct_instance(self, **kwargs):
+               """Apply cleaned data from the formfields generated by valid_formfields to oneself."""
                raise NotImplementedError
        
        def __unicode__(self):
                raise NotImplementedError
        
        def __unicode__(self):
@@ -73,17 +78,22 @@ attribute_value_limiter = ContentTypeSubclassLimiter(AttributeValue)
 
 
 class JSONValue(AttributeValue):
 
 
 class JSONValue(AttributeValue):
-       value = JSONField() #verbose_name='Value (JSON)', help_text='This value must be valid JSON.')
+       value = JSONField(verbose_name='Value (JSON)', help_text='This value must be valid JSON.', default='null')
        
        def __unicode__(self):
                return smart_str(self.value)
        
        
        def __unicode__(self):
                return smart_str(self.value)
        
-       def value_formfield(self, **kwargs):
-               kwargs['initial'] = self.value_json
-               return self._meta.get_field('value').formfield(**kwargs)
+       def value_formfields(self):
+               kwargs = {'initial': self.value_json}
+               field = self._meta.get_field('value')
+               return {field.name: field.formfield(**kwargs)}
        
        
-       def apply_data(self, cleaned_data):
-               self.value = cleaned_data.get('value', None)
+       def construct_instance(self, **kwargs):
+               field_name = self._meta.get_field('value').name
+               self.set_value(kwargs.pop(field_name, None))
+       
+       def set_value(self, value):
+               self.value = value
        
        class Meta:
                app_label = 'philo'
        
        class Meta:
                app_label = 'philo'
@@ -94,19 +104,33 @@ class ForeignKeyValue(AttributeValue):
        object_id = models.PositiveIntegerField(verbose_name='Value ID', null=True, blank=True)
        value = generic.GenericForeignKey()
        
        object_id = models.PositiveIntegerField(verbose_name='Value ID', null=True, blank=True)
        value = generic.GenericForeignKey()
        
-       def value_formfield(self, form_class=forms.ModelChoiceField, **kwargs):
-               if self.content_type is None:
-                       return None
-               kwargs.update({'initial': self.object_id, 'required': False})
-               return form_class(self.content_type.model_class()._default_manager.all(), **kwargs)
-       
-       def apply_data(self, cleaned_data):
-               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.
+       def value_formfields(self):
+               field = self._meta.get_field('content_type')
+               fields = {field.name: field.formfield(initial=getattr(self.content_type, 'pk', None))}
+               
+               if self.content_type:
+                       kwargs = {
+                               'initial': self.object_id,
+                               'required': False,
+                               'queryset': self.content_type.model_class()._default_manager.all()
+                       }
+                       fields['value'] = forms.ModelChoiceField(**kwargs)
+               return fields
+       
+       def construct_instance(self, **kwargs):
+               field_name = self._meta.get_field('content_type').name
+               ct = kwargs.pop(field_name, None)
+               if ct is None or ct != self.content_type:
                        self.object_id = None
                        self.object_id = None
+                       self.content_type = ct
+               else:
+                       value = kwargs.pop('value', None)
+                       self.set_value(value)
+                       if value is None:
+                               self.content_type = ct
+       
+       def set_value(self, value):
+               self.value = value
        
        class Meta:
                app_label = 'philo'
        
        class Meta:
                app_label = 'philo'
@@ -154,19 +178,29 @@ class ManyToManyValue(AttributeValue):
        
        value = property(get_value, set_value)
        
        
        value = property(get_value, set_value)
        
-       def value_formfield(self, form_class=forms.ModelMultipleChoiceField, **kwargs):
-               if self.content_type is None:
-                       return None
-               kwargs.update({'initial': self.get_object_id_list(), 'required': False})
-               return form_class(self.content_type.model_class()._default_manager.all(), **kwargs)
-       
-       def apply_data(self, cleaned_data):
-               if 'value' in cleaned_data and cleaned_data['value'] is not None:
-                       self.value = cleaned_data['value']
+       def value_formfields(self):
+               field = self._meta.get_field('content_type')
+               fields = {field.name: field.formfield(initial=getattr(self.content_type, 'pk', None))}
+               
+               if self.content_type:
+                       kwargs = {
+                               'initial': self.get_object_id_list(),
+                               'required': False,
+                               'queryset': self.content_type.model_class()._default_manager.all()
+                       }
+                       fields['value'] = forms.ModelMultipleChoiceField(**kwargs)
+               return fields
+       
+       def construct_instance(self, **kwargs):
+               field_name = self._meta.get_field('content_type').name
+               ct = kwargs.pop(field_name, None)
+               if ct is None or ct != self.content_type:
+                       self.values.clear()
+                       self.content_type = ct
                else:
                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.value = []
+                       value = kwargs.get('value', self.content_type.model_class()._default_manager.none())
+                       self.set_value(value)
+       construct_instance.alters_data = True
        
        class Meta:
                app_label = 'philo'
        
        class Meta:
                app_label = 'philo'
@@ -245,37 +279,6 @@ class Entity(models.Model):
        def attributes(self):
                return QuerySetMapper(self.attribute_set.all())
        
        def attributes(self):
                return QuerySetMapper(self.attribute_set.all())
        
-       @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
-       
-       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 field, value in self._added_attribute_registry.items():
-                       try:
-                               attribute = self.attribute_set.get(key__exact=field.key)
-                       except Attribute.DoesNotExist:
-                               attribute = Attribute()
-                               attribute.entity = self
-                               attribute.key = field.key
-                       
-                       field.set_attribute_value(attribute, value)
-                       attribute.save()
-               self._added_attribute_registry.clear()
-       
        class Meta:
                abstract = True
 
        class Meta:
                abstract = True