Generated: Wed 2013-03-13 10:33 CET
Source file: /media/Envs/Envs/filer-gallery/lib/python2.7/site-packages/mptt/utils.py
Stats: 0 executed, 56 missed, 4 excluded, 122 ignored
"""Utilities for working with lists of model instances which representtrees."""import copyimport csvimport itertoolsimport sys__all__ = ('previous_current_next', 'tree_item_iterator', 'drilldown_tree_for_node')def previous_current_next(items): """ From http://www.wordaligned.org/articles/zippy-triples-served-with-python Creates an iterator which returns (previous, current, next) triples, with ``None`` filling in when there is no previous or next available. """ extend = itertools.chain([None], items, [None]) previous, current, next = itertools.tee(extend, 3) try: current.next() next.next() next.next() except StopIteration: pass return itertools.izip(previous, current, next)def tree_item_iterator(items, ancestors=False): """ Given a list of tree items, iterates over the list, generating two-tuples of the current tree item and a ``dict`` containing information about the tree structure around the item, with the following keys: ``'new_level'`` ``True`` if the current item is the start of a new level in the tree, ``False`` otherwise. ``'closed_levels'`` A list of levels which end after the current item. This will be an empty list if the next item is at the same level as the current item. If ``ancestors`` is ``True``, the following key will also be available: ``'ancestors'`` A list of unicode representations of the ancestors of the current node, in descending order (root node first, immediate parent last). For example: given the sample tree below, the contents of the list which would be available under the ``'ancestors'`` key are given on the right:: Books -> [] Sci-fi -> [u'Books'] Dystopian Futures -> [u'Books', u'Sci-fi'] """ structure = {} opts = None first_item_level = 0 for previous, current, next in previous_current_next(items): if opts is None: opts = current._mptt_meta current_level = getattr(current, opts.level_attr) if previous: structure['new_level'] = (getattr(previous, opts.level_attr) < current_level) if ancestors: # If the previous node was the end of any number of # levels, remove the appropriate number of ancestors # from the list. if structure['closed_levels']: structure['ancestors'] = \ structure['ancestors'][:-len(structure['closed_levels'])] # If the current node is the start of a new level, add its # parent to the ancestors list. if structure['new_level']: structure['ancestors'].append(unicode(previous)) else: structure['new_level'] = True if ancestors: # Set up the ancestors list on the first item structure['ancestors'] = [] first_item_level = current_level if next: structure['closed_levels'] = range(current_level, getattr(next, opts.level_attr), -1) else: # All remaining levels need to be closed structure['closed_levels'] = range(current_level, first_item_level - 1, -1) # Return a deep copy of the structure dict so this function can # be used in situations where the iterator is consumed # immediately. yield current, copy.deepcopy(structure)def drilldown_tree_for_node(node, rel_cls=None, rel_field=None, count_attr=None, cumulative=False): """ Creates a drilldown tree for the given node. A drilldown tree consists of a node's ancestors, itself and its immediate children, all in tree order. Optional arguments may be given to specify a ``Model`` class which is related to the node's class, for the purpose of adding related item counts to the node's children: ``rel_cls`` A ``Model`` class which has a relation to the node's class. ``rel_field`` The name of the field in ``rel_cls`` which holds the relation to the node's class. ``count_attr`` The name of an attribute which should be added to each child in the drilldown tree, containing a count of how many instances of ``rel_cls`` are related through ``rel_field``. ``cumulative`` If ``True``, the count will be for each child and all of its descendants, otherwise it will be for each child itself. """ if rel_cls and rel_field and count_attr: children = node._tree_manager.add_related_count( node.get_children(), rel_cls, rel_field, count_attr, cumulative) else: children = node.get_children() return itertools.chain(node.get_ancestors(), [node], children)def print_debug_info(qs): """ Given an mptt queryset, prints some debug information to stdout. Use this when things go wrong. Please include the output from this method when filing bug issues. """ opts = qs.model._mptt_meta writer = csv.writer(sys.stdout) header = ( 'pk', opts.level_attr, '%s_id' % opts.parent_attr, opts.tree_id_attr, opts.left_attr, opts.right_attr, 'pretty', ) writer.writerow(header) for n in qs.order_by('tree_id', 'lft'): level = getattr(n, opts.level_attr) row = [] for field in header[:-1]: row.append(getattr(n, field)) row.append('%s%s' % ('- ' * level, unicode(n).encode('utf-8'))) writer.writerow(row)# NOTE we don't support django 1.1 anymore, so this stuff is likely to get removed soondef _exists(qs): """ For Django 1.1 compatibility. (QuerySet.exists() was added in 1.2) This is not part of the supported mptt API, it may be removed without warning. """ if hasattr(qs, 'exists'): return qs.exists() else: qs = qs.extra(select={'_exists_check': '1'}).values_list('_exists_check', flat=True)[:1] return bool(len(qs))