X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/3d786c6d8c1bd3685ac328c7f4b811c13ea60e1a..61b73fe068172f02d6c47e2b5387161919ec9618:/philo/models/base.py diff --git a/philo/models/base.py b/philo/models/base.py index 2f798ae..e7918f5 100644 --- a/philo/models/base.py +++ b/philo/models/base.py @@ -16,23 +16,7 @@ from philo.utils.entities import AttributeMapper, TreeAttributeMapper from philo.validators import json_validator -__all__ = ('Tag', 'value_content_type_limiter', 'register_value_model', 'unregister_value_model', 'JSONValue', 'ForeignKeyValue', 'ManyToManyValue', 'Attribute', 'Entity', 'TreeEntity', 'SlugTreeEntity') - - -class Tag(models.Model): - """A simple, generic model for tagging.""" - #: A CharField (max length 255) which contains the name of the tag. - name = models.CharField(max_length=255) - #: A CharField (max length 255) which contains the tag's unique slug. - slug = models.SlugField(max_length=255, unique=True) - - def __unicode__(self): - """Returns the value of the :attr:`name` field""" - return self.name - - class Meta: - app_label = 'philo' - ordering = ('name',) +__all__ = ('value_content_type_limiter', 'register_value_model', 'unregister_value_model', 'JSONValue', 'ForeignKeyValue', 'ManyToManyValue', 'Attribute', 'Entity', 'TreeEntity', 'SlugTreeEntity') #: An instance of :class:`.ContentTypeRegistryLimiter` which is used to track the content types which can be related to by :class:`ForeignKeyValue`\ s and :class:`ManyToManyValue`\ s. @@ -44,9 +28,6 @@ def register_value_model(model): value_content_type_limiter.register_class(model) -register_value_model(Tag) - - def unregister_value_model(model): """Registers a model as a valid content type for a :class:`ForeignKeyValue` or :class:`ManyToManyValue` through the :data:`value_content_type_limiter`.""" value_content_type_limiter.unregister_class(model) @@ -458,11 +439,12 @@ class TreeEntity(Entity, MPTTModel): objects = TreeEntityManager() parent = models.ForeignKey('self', related_name='children', null=True, blank=True) - def get_path(self, root=None, pathsep='/', field='slug'): + def get_path(self, root=None, pathsep='/', field='pk', memoize=True): """ :param root: Only return the path since this object. :param pathsep: The path separator to use when constructing an instance's path :param field: The field to pull path information from for each ancestor. + :param memoize: Whether to use memoized results. Since, in most cases, the ancestors of a TreeEntity will not change over the course of an instance's lifetime, this defaults to ``True``. :returns: A string representation of an object's path. """ @@ -470,18 +452,33 @@ class TreeEntity(Entity, MPTTModel): if root == self: return '' - if root is None and self.is_root_node(): + parent_id = getattr(self, "%s_id" % self._mptt_meta.parent_attr) + if getattr(root, 'pk', None) == parent_id: return getattr(self, field, '?') if root is not None and not self.is_descendant_of(root): raise AncestorDoesNotExist(root) + if memoize: + memo_args = (parent_id, getattr(root, 'pk', None), pathsep, getattr(self, field, '?')) + try: + return self._path_memo[memo_args] + except AttributeError: + self._path_memo = {} + except KeyError: + pass + qs = self.get_ancestors(include_self=True) if root is not None: qs = qs.filter(**{'%s__gt' % self._mptt_meta.level_attr: root.get_level()}) - return pathsep.join([getattr(parent, field, '?') for parent in qs]) + path = pathsep.join([getattr(parent, field, '?') for parent in qs]) + + if memoize: + self._path_memo[memo_args] = path + + return path path = property(get_path) def get_attribute_mapper(self, mapper=None): @@ -500,7 +497,7 @@ class TreeEntity(Entity, MPTTModel): """ if mapper is None: - if self.parent: + if getattr(self, "%s_id" % self._mptt_meta.parent_attr): mapper = TreeAttributeMapper else: mapper = AttributeMapper @@ -522,12 +519,12 @@ class SlugTreeEntity(TreeEntity): objects = SlugTreeEntityManager() slug = models.SlugField(max_length=255) - def get_path(self, root=None, pathsep='/', field='slug'): - return super(SlugTreeEntity, self).get_path(root, pathsep, field) + def get_path(self, root=None, pathsep='/', field='slug', memoize=True): + return super(SlugTreeEntity, self).get_path(root, pathsep, field, memoize) path = property(get_path) def clean(self): - if self.parent is None: + if getattr(self, "%s_id" % self._mptt_meta.parent_attr) is None: try: self._default_manager.exclude(pk=self.pk).get(slug=self.slug, parent__isnull=True) except self.DoesNotExist: