X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/1422f0d2c8325b2c4d6781bd3c7b21a3d5873b90..834e27b62ba09014f91feabe89da08adb472ce9e:/forms/entities.py diff --git a/forms/entities.py b/forms/entities.py index a392e45..b6259a3 100644 --- a/forms/entities.py +++ b/forms/entities.py @@ -1,13 +1,9 @@ -from django import forms -from django.contrib.contenttypes.generic import BaseGenericInlineFormSet -from django.contrib.contenttypes.models import ContentType from django.forms.models import ModelFormMetaclass, ModelForm from django.utils.datastructures import SortedDict -from philo.models import Attribute from philo.utils import fattr -__all__ = ('EntityForm', 'AttributeForm', 'AttributeInlineFormSet') +__all__ = ('EntityForm',) def proxy_fields_for_entity_model(entity_model, fields=None, exclude=None, widgets=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)): @@ -47,9 +43,15 @@ class EntityFormBase(ModelForm): _old_metaclass_new = ModelFormMetaclass.__new__ def _new_metaclass_new(cls, name, bases, attrs): + formfield_callback = attrs.get('formfield_callback', lambda f, **kwargs: f.formfield(**kwargs)) new_class = _old_metaclass_new(cls, name, bases, attrs) - if issubclass(new_class, EntityFormBase) and new_class._meta.model: - new_class.base_fields.update(proxy_fields_for_entity_model(new_class._meta.model, new_class._meta.fields, new_class._meta.exclude, new_class._meta.widgets)) # don't pass in formfield_callback + opts = new_class._meta + if issubclass(new_class, EntityFormBase) and opts.model: + # "override" proxy fields with declared fields by excluding them if there's a name conflict. + exclude = (list(opts.exclude or []) + new_class.declared_fields.keys()) or None + proxy_fields = proxy_fields_for_entity_model(opts.model, opts.fields, exclude, opts.widgets, formfield_callback) # don't pass in formfield_callback + new_class.proxy_fields = proxy_fields + new_class.base_fields.update(proxy_fields) return new_class ModelFormMetaclass.__new__ = staticmethod(_new_metaclass_new) @@ -88,88 +90,10 @@ class EntityForm(EntityFormBase): # Would inherit from ModelForm directly if it continue if self._meta.exclude and f.name in self._meta.exclude: continue - setattr(instance, f.attname, cleaned_data[f.name]) + setattr(instance, f.attname, f.get_storage_value(cleaned_data[f.name])) if commit: instance.save() self.save_m2m() - return instance - - - def apply_data(self, cleaned_data): - self.value = cleaned_data.get('value', None) - - 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. - self.object_id = None - - 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. - self.value = [] - -class AttributeForm(ModelForm): - """ - This class handles an attribute's fields as well as the fields for its value (if there is one.) - The fields defined will vary depending on the value type, but the fields for defining the value - (i.e. value_content_type and value_object_id) will always be defined. Except that value_object_id - will never be defined. BLARGH! - """ - def __init__(self, *args, **kwargs): - super(AttributeForm, self).__init__(*args, **kwargs) - - # This is necessary because model forms store changes to self.instance in their clean method. - # Mutter mutter. - value = self.instance.value - self._cached_value_ct = self.instance.value_content_type - self._cached_value = value - - # If there is a value, pull in its fields. - if value is not None: - self.value_fields = value.value_formfields() - self.fields.update(self.value_fields) - - def save(self, *args, **kwargs): - # At this point, the cleaned_data has already been stored on self.instance. - - if self.instance.value_content_type != self._cached_value_ct: - # The value content type has changed. Clear the old value, if there was one. - if self._cached_value: - self._cached_value.delete() - - # Clear the submitted value, if any. - self.cleaned_data.pop('value', None) - - # Now create a new value instance so that on next instantiation, the form will - # know what fields to add. - if self.instance.value_content_type is not None: - self.instance.value = self.instance.value_content_type.model_class().objects.create() - elif self.instance.value is not None: - # The value content type is the same, but one of the value fields has changed. - - # Use construct_instance to apply the changes from the cleaned_data to the value instance. - fields = self.value_fields.keys() - if set(fields) & set(self.changed_data): - self.instance.value.construct_instance(**dict([(key, self.cleaned_data[key]) for key in fields])) - self.instance.value.save() - - return super(AttributeForm, self).save(*args, **kwargs) - - class Meta: - model = Attribute - - -class AttributeInlineFormSet(BaseGenericInlineFormSet): - "Necessary to force the GenericInlineFormset to use the form's save method for new objects." - def save_new(self, form, commit): - setattr(form.instance, self.ct_field.get_attname(), ContentType.objects.get_for_model(self.instance).pk) - setattr(form.instance, self.ct_fk_field.get_attname(), self.instance.pk) - return form.save() \ No newline at end of file + return instance \ No newline at end of file