'Walk the list of names and turns them into PathInfo tuples. A single
name in \'names\' can generate multiple PathInfos (m2m, for example).
\'names\' is the path of names to travel, \'opts\' is the model Options we
start the name resolving from, \'allow_many\' is as for setup_joins().
If fail_on_missing is set to True, then a name that can\'t be resolved
will generate a FieldError.
Return a list of PathInfo tuples. In addition return the final field
(the last used join field) and target (which is a field guaranteed to
contain the same value as the final field). Finally, return those names
that weren\'t found (which are likely transforms and the final lookup).'

def names_to_path(self, names, opts, allow_many=True, fail_on_missing=False):

    (path, names_with_path) = ([], [])
    for (pos, name) in enumerate(names):
        cur_names_with_path = (name, [])
        if (name == 'pk'):
            name = opts.pk.name
        field = None
        try:
            field = opts.get_field(name)
        except FieldDoesNotExist:
            if (name in self.annotation_select):
                field = self.annotation_select[name].output_field
        if (field is not None):
            if (field.is_relation and (not field.related_model)):
                raise FieldError(('Field    %r    does    not    generate    an    automatic    reverse    relation    and    therefore    cannot    be    used    for    reverse    querying.    If    it    is    a    GenericForeignKey,    consider    adding    a    GenericRelation.' % name))
            try:
                model = field.model._meta.concrete_model
            except AttributeError:
                model = None
        else:
            pos -= 1
            if ((pos == (-1)) or fail_on_missing):
                field_names = list(get_field_names_from_opts(opts))
                available = sorted((field_names + list(self.annotation_select)))
                raise FieldError(("Cannot    resolve    keyword    '%s'    into    field.    Choices    are:    %s" % (name, ',    '.join(available))))
            break
        if (model is not opts.model):
            path_to_parent = opts.get_path_to_parent(model)
            if path_to_parent:
                path.extend(path_to_parent)
                cur_names_with_path[1].extend(path_to_parent)
                opts = path_to_parent[(-1)].to_opts
        if hasattr(field, 'get_path_info'):
            pathinfos = field.get_path_info()
            if (not allow_many):
                for (inner_pos, p) in enumerate(pathinfos):
                    if p.m2m:
                        cur_names_with_path[1].extend(pathinfos[0:(inner_pos + 1)])
                        names_with_path.append(cur_names_with_path)
                        raise MultiJoin((pos + 1), names_with_path)
            last = pathinfos[(-1)]
            path.extend(pathinfos)
            final_field = last.join_field
            opts = last.to_opts
            targets = last.target_fields
            cur_names_with_path[1].extend(pathinfos)
            names_with_path.append(cur_names_with_path)
        else:
            final_field = field
            targets = (field,)
            if (fail_on_missing and ((pos + 1) != len(names))):
                raise FieldError(("Cannot    resolve    keyword    %r    into    field.    Join    on    '%s'    not    permitted." % (names[(pos + 1)], name)))
            break
    return (path, final_field, targets, names[(pos + 1):])
