def get_cached_trees(queryset):
    """
    Takes a list/queryset of model objects in MPTT left (depth-first) order and
    caches the children and parent on each node. This allows up and down
    traversal through the tree without the need for further queries. Use cases
    include using a recursively included template or arbitrarily traversing
    trees.

    NOTE: nodes _must_ be passed in the correct (depth-first) order. If they aren't,
    a ValueError will be raised.

    Returns a list of top-level nodes. If a single tree was provided in its
    entirety, the list will of course consist of just the tree's root node.

    For filtered querysets, if no ancestors for a node are included in the
    queryset, it will appear in the returned list as a top-level node.

    Aliases to this function are also available:

    ``mptt.templatetags.mptt_tag.cache_tree_children``
       Use for recursive rendering in templates.

    ``mptt.querysets.TreeQuerySet.get_cached_trees``
       Useful for chaining with queries; e.g.,
       `Node.objects.filter(**kwargs).get_cached_trees()`

    FIXME: This method fixed the original `mptt.utils.get_cached_trees` method
    as it doesn't consider filtered querysets that might not contain all tree nodes

    """
    current_path = []
    top_nodes = []
    if queryset:
        parent_attr = queryset[0]._mptt_meta.parent_attr
        root_level = None
        is_filtered = hasattr(queryset, 'query'
            ) and queryset.query.has_filters()
        for obj in queryset:
            node_level = obj.get_level()
            if root_level is None or is_filtered and node_level < root_level:
                root_level = node_level
            elif node_level < root_level:
                raise ValueError('Node %s not in depth-first order' % (type
                    (queryset),))
            obj._cached_children = []
            while len(current_path) > node_level - root_level:
                current_path.pop(-1)
            if node_level == root_level:
                top_nodes.append(obj)
            else:
                _parent = current_path[-1]
                setattr(obj, parent_attr, _parent)
                _parent._cached_children.append(obj)
                if root_level == 0:
                    setattr(obj, '_mptt_use_cached_ancestors', True)
            current_path.append(obj)
    return top_nodes
