'Fill in the information needed for a select_related query. The current
depth is measured as the number of connections away from the root model
(for example, cur_depth=1 means we are looking at models with direct
connections to the root model).'

def get_related_selections(self, select, opts=None, root_alias=None, cur_depth=1, requested=None, restricted=None):

    def _get_field_choices():
        direct_choices = (f.name for f in opts.fields if f.is_relation)
        reverse_choices = (f.field.related_query_name() for f in opts.related_objects if f.field.unique)
        return chain(direct_choices, reverse_choices)
    related_klass_infos = []
    if ((not restricted) and self.query.max_depth and (cur_depth > self.query.max_depth)):
        return related_klass_infos
    if (not opts):
        opts = self.query.get_meta()
        root_alias = self.query.get_initial_alias()
    only_load = self.query.get_loaded_field_names()
    fields_found = set()
    if (requested is None):
        if isinstance(self.query.select_related, dict):
            requested = self.query.select_related
            restricted = True
        else:
            restricted = False
    def get_related_klass_infos(klass_info, related_klass_infos):
        klass_info['related_klass_infos'] = related_klass_infos
    for f in opts.fields:
        field_model = f.model._meta.concrete_model
        fields_found.add(f.name)
        if restricted:
            next = requested.get(f.name, {})
            if (not f.is_relation):
                if (next or (f.name in requested)):
                    raise FieldError(("Non-relational    field    given    in    select_related:    '%s'.    Choices    are:    %s" % (f.name, (',    '.join(_get_field_choices()) or '(none)'))))
        else:
            next = False
        if (not select_related_descend(f, restricted, requested, only_load.get(field_model))):
            continue
        klass_info = {'model': f.remote_field.model, 'field': f, 'reverse': False, 'from_parent': False}
        related_klass_infos.append(klass_info)
        select_fields = []
        (_, _, _, joins, _) = self.query.setup_joins([f.name], opts, root_alias)
        alias = joins[(-1)]
        columns = self.get_default_columns(start_alias=alias, opts=f.remote_field.model._meta)
        for col in columns:
            select_fields.append(len(select))
            select.append((col, None))
        klass_info['select_fields'] = select_fields
        next_klass_infos = self.get_related_selections(select, f.remote_field.model._meta, alias, (cur_depth + 1), next, restricted)
        get_related_klass_infos(klass_info, next_klass_infos)
    if restricted:
        related_fields = [(o.field, o.related_model) for o in opts.related_objects if (o.field.unique and (not o.many_to_many))]
        for (f, model) in related_fields:
            if (not select_related_descend(f, restricted, requested, only_load.get(model), reverse=True)):
                continue
            related_field_name = f.related_query_name()
            fields_found.add(related_field_name)
            join_info = self.query.setup_joins([related_field_name], opts, root_alias)
            alias = join_info.joins[(-1)]
            from_parent = (issubclass(model, opts.model) and (model is not opts.model))
            klass_info = {'model': model, 'field': f, 'reverse': True, 'from_parent': from_parent}
            related_klass_infos.append(klass_info)
            select_fields = []
            columns = self.get_default_columns(start_alias=alias, opts=model._meta, from_parent=opts.model)
            for col in columns:
                select_fields.append(len(select))
                select.append((col, None))
            klass_info['select_fields'] = select_fields
            next = requested.get(f.related_query_name(), {})
            next_klass_infos = self.get_related_selections(select, model._meta, alias, (cur_depth + 1), next, restricted)
            get_related_klass_infos(klass_info, next_klass_infos)
        fields_not_found = set(requested).difference(fields_found)
        if fields_not_found:
            invalid_fields = (("'%s'" % s) for s in fields_not_found)
            raise FieldError(('Invalid    field    name(s)    given    in    select_related:    %s.    Choices    are:    %s' % (',    '.join(invalid_fields), (',    '.join(_get_field_choices()) or '(none)'))))
    return related_klass_infos
