Recursively descends the tree/forest (starting from each root node)
            in order to find a :class:`CTENode` which corresponds to the given
            `path`. The path is expected to be an iterable of tuples, called
            path components, consisting of attribute values with which to filter
            through the QuerySet API. The name of the attribute to which each
            value corresponds is specified in `attributes`, which is expected
            to conform to Django's QuerySet API for the filter semantics. Each
            value in the path component tuple will be mapped to its
            corresponding attribute name before being passed to the filter
            method.

            For example, if the node model features the integer field ``x``
            and the boolean field ``y``, we can drill down in the following way:

                drilldown(('x__gte', 'y'),[(35, True), (37, False)])

            The simplest form of drilldown is to match with equality on a single
            attribute, such as ``name``, as in the following example:

                drilldown(('name',), [('path',), ('to',), ('my',), ('node',)])

            Don't forget the trailing comma if specifying singleton tuples! If
            you need very simple, one-attribute path components, it is suggested
            you extend the manager with your own convenience method; the above
            will, for instance, become:

                def drilldown_by_name(self, path):
                    return self.drilldown(('name',),
                        [(component,) for component in path])

            Failure to find the required node results in a :class:`DoesNotExist`
            exception being raised.

            An empty path will result in the first root node being returned (if
            at least one root node exists).

def drilldown(self, attributes, path):
        """ Recursively descends the tree/forest (starting from each root node)
            in order to find a :class:`CTENode` which corresponds to the given
            `path`. The path is expected to be an iterable of tuples, called
            path components, consisting of attribute values with which to filter
            through the QuerySet API. The name of the attribute to which each
            value corresponds is specified in `attributes`, which is expected
            to conform to Django's QuerySet API for the filter semantics. Each
            value in the path component tuple will be mapped to its
            corresponding attribute name before being passed to the filter
            method.

            For example, if the node model features the integer field ``x``
            and the boolean field ``y``, we can drill down in the following way:

                drilldown(('x__gte', 'y'),[(35, True), (37, False)])

            The simplest form of drilldown is to match with equality on a single
            attribute, such as ``name``, as in the following example:

                drilldown(('name',), [('path',), ('to',), ('my',), ('node',)])

            Don't forget the trailing comma if specifying singleton tuples! If
            you need very simple, one-attribute path components, it is suggested
            you extend the manager with your own convenience method; the above
            will, for instance, become:

                def drilldown_by_name(self, path):
                    return self.drilldown(('name',),
                        [(component,) for component in path])

            Failure to find the required node results in a :class:`DoesNotExist`
            exception being raised.

            An empty path will result in the first root node being returned (if
            at least one root node exists).
        """

        # empty path result in first root, if present
        if len(path) == 0:
            try:
                return self.roots()[0]
            except IndexError:
                raise self.model.DoesNotExist

        # bootstrap with the first component, then iterate through the remaining
        # components in the path as long as each child node is found
        component = path[0]
        current = None

        # mapping of attribute names with values, as per QuerySet filter
        def attrs(component):
            return dict(zip(attributes, component))

        # find the root corresponding to the bootstrapped initial path component
        try:
            root = self.roots().filter(**attrs(component))[0]
        except IndexError:
            raise self.model.DoesNotExist

        # proceed to drill down until path components are exhausted
        current = root
        for component in path[1:]:
            try:
                current = current.children.filter(**attrs(component))[0]
            except IndexError:
                raise self.model.DoesNotExist
        return current