X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/345e9cbecf62cf3bc7f697e33512e499a5b94fe4..585c315fde9781b72e1bacd430877c1e5b110e90:/models/base.py diff --git a/models/base.py b/models/base.py index 5d9d761..1b6e60f 100644 --- a/models/base.py +++ b/models/base.py @@ -46,7 +46,12 @@ def unregister_value_model(model): class AttributeValue(models.Model): - attribute = generic.GenericRelation('Attribute', content_type_field='value_content_type', object_id_field='value_object_id') + attribute_set = generic.GenericRelation('Attribute', content_type_field='value_content_type', object_id_field='value_object_id') + + @property + def attribute(self): + return self.attribute_set.all()[0] + def apply_data(self, data): raise NotImplementedError @@ -81,7 +86,7 @@ class JSONValue(AttributeValue): class ForeignKeyValue(AttributeValue): - content_type = models.ForeignKey(ContentType, related_name='foreign_key_value_set', limit_choices_to=value_content_type_limiter, verbose_name='Value type', null=True, blank=True) + content_type = models.ForeignKey(ContentType, limit_choices_to=value_content_type_limiter, verbose_name='Value type', null=True, blank=True) object_id = models.PositiveIntegerField(verbose_name='Value ID', null=True, blank=True) value = generic.GenericForeignKey() @@ -104,14 +109,14 @@ class ForeignKeyValue(AttributeValue): class ManyToManyValue(AttributeValue): - 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) + content_type = models.ForeignKey(ContentType, limit_choices_to=value_content_type_limiter, verbose_name='Value type', null=True, blank=True) + values = models.ManyToManyField(ForeignKeyValue, blank=True, null=True) def get_object_id_list(self): - if not self.object_ids: + if not self.values.count(): return [] else: - return self.object_ids.split(',') + return self.values.values_list('object_id', flat=True) def get_value(self): if self.content_type is None: @@ -120,13 +125,23 @@ class ManyToManyValue(AttributeValue): return self.content_type.model_class()._default_manager.filter(id__in=self.get_object_id_list()) def set_value(self, value): - if value is None: - self.object_ids = "" - return - if not isinstance(value, models.query.QuerySet): - raise TypeError("Value must be a QuerySet.") - self.content_type = ContentType.objects.get_for_model(value.model) - self.object_ids = ','.join([`value` for value in value.values_list('id', flat=True)]) + # Value is probably a queryset - but allow any iterable. + + # These lines shouldn't be necessary; however, if value is an EmptyQuerySet, + # the code won't work without them. Unclear why... + if not value: + value = [] + + if isinstance(value, models.query.QuerySet): + value = value.values_list('id', flat=True) + + self.values.filter(~models.Q(object_id__in=value)).delete() + current = self.get_object_id_list() + + for v in value: + if v in current: + continue + self.values.create(content_type=self.content_type, object_id=v) value = property(get_value, set_value) @@ -137,7 +152,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.value = [] class Meta: app_label = 'philo' @@ -154,29 +174,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) @@ -192,11 +189,15 @@ class QuerySetMapper(object, DictMixin): def __getitem__(self, key): try: - return self.queryset.get(key__exact=key).value + value = self.queryset.get(key__exact=key).value except ObjectDoesNotExist: if self.passthrough is not None: return self.passthrough.__getitem__(key) raise KeyError + else: + if value is not None: + return value.value + return value def keys(self): keys = set(self.queryset.values_list('key', flat=True).distinct()) @@ -233,7 +234,7 @@ class Entity(models.Model): @property def attributes(self): - return QuerySetMapper(self.attribute_set) + return QuerySetMapper(self.attribute_set.all()) @property def _added_attribute_registry(self): @@ -254,14 +255,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() @@ -319,22 +321,15 @@ class TreeModel(models.Model): return False def get_path(self, root=None, pathsep='/', field='slug'): - if root is not None: - if not self.has_ancestor(root): - raise AncestorDoesNotExist(root) - path = '' - parent = self - while parent and parent != root: - path = getattr(parent, field, '?') + pathsep + path - parent = parent.parent - return path - else: - path = getattr(self, field, '?') - parent = self.parent - while parent and parent != root: - path = getattr(parent, field, '?') + pathsep + path - parent = parent.parent - return path + if root is not None and not self.has_ancestor(root): + raise AncestorDoesNotExist(root) + + path = getattr(self, field, '?') + parent = self.parent + while parent and parent != root: + path = getattr(parent, field, '?') + pathsep + path + parent = parent.parent + return path path = property(get_path) def __unicode__(self): @@ -349,14 +344,8 @@ class TreeEntity(Entity, TreeModel): @property def attributes(self): if self.parent: - return QuerySetMapper(self.attribute_set, passthrough=self.parent.attributes) + return QuerySetMapper(self.attribute_set.all(), passthrough=self.parent.attributes) return super(TreeEntity, self).attributes - @property - def relationships(self): - if self.parent: - return QuerySetMapper(self.relationship_set, passthrough=self.parent.relationships) - return super(TreeEntity, self).relationships - class Meta: abstract = True \ No newline at end of file