'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 fill_related_selections(self, opts=None, root_alias=None, cur_depth=1, used=None, requested=None, restricted=None, nullable=None, dupe_set=None, avoid_set=None):

    if ((not restricted) and self.query.max_depth and (cur_depth > self.query.max_depth)):
        return
    if (not opts):
        opts = self.query.get_meta()
        root_alias = self.query.get_initial_alias()
        self.query.related_select_cols = []
        self.query.related_select_fields = []
    if (not used):
        used = set()
    if (dupe_set is None):
        dupe_set = set()
    if (avoid_set is None):
        avoid_set = set()
    orig_dupe_set = dupe_set
    only_load = self.query.get_loaded_field_names()
    if (requested is None):
        if isinstance(self.query.select_related, dict):
            requested = self.query.select_related
            restricted = True
        else:
            restricted = False
    for (f, model) in opts.get_fields_with_model():
        field_model = (model or f.model)
        if (not select_related_descend(f, restricted, requested, only_load.get(field_model))):
            continue
        avoid = avoid_set.copy()
        dupe_set = orig_dupe_set.copy()
        table = f.rel.to._meta.db_table
        promote = (nullable or f.null)
        if model:
            int_opts = opts
            alias = root_alias
            alias_chain = []
            for int_model in opts.get_base_chain(model):
                if (not int_opts.parents[int_model]):
                    int_opts = int_model._meta
                    continue
                lhs_col = int_opts.parents[int_model].column
                dedupe = (lhs_col in opts.duplicate_targets)
                if dedupe:
                    avoid.update(self.query.dupe_avoidance.get((id(opts), lhs_col), ()))
                    dupe_set.add((opts, lhs_col))
                int_opts = int_model._meta
                alias = self.query.join((alias, int_opts.db_table, lhs_col, int_opts.pk.column), exclusions=used, promote=promote)
                alias_chain.append(alias)
                for (dupe_opts, dupe_col) in dupe_set:
                    self.query.update_dupe_avoidance(dupe_opts, dupe_col, alias)
        else:
            alias = root_alias
        dedupe = (f.column in opts.duplicate_targets)
        if (dupe_set or dedupe):
            avoid.update(self.query.dupe_avoidance.get((id(opts), f.column), ()))
            if dedupe:
                dupe_set.add((opts, f.column))
        alias = self.query.join((alias, table, f.column, f.rel.get_related_field().column), exclusions=used.union(avoid), promote=promote)
        used.add(alias)
        (columns, aliases) = self.get_default_columns(start_alias=alias, opts=f.rel.to._meta, as_pairs=True)
        self.query.related_select_cols.extend(columns)
        self.query.related_select_fields.extend(f.rel.to._meta.fields)
        if restricted:
            next = requested.get(f.name, {})
        else:
            next = False
        new_nullable = (f.null or promote)
        for (dupe_opts, dupe_col) in dupe_set:
            self.query.update_dupe_avoidance(dupe_opts, dupe_col, alias)
        self.fill_related_selections(f.rel.to._meta, alias, (cur_depth + 1), used, next, restricted, new_nullable, dupe_set, avoid)
    if restricted:
        related_fields = [(o.field, o.model) for o in opts.get_all_related_objects() if o.field.unique]
        for (f, model) in related_fields:
            if (not select_related_descend(f, restricted, requested, only_load.get(model), reverse=True)):
                continue
            avoid = avoid_set.copy()
            dupe_set = orig_dupe_set.copy()
            table = model._meta.db_table
            int_opts = opts
            alias = root_alias
            alias_chain = []
            chain = opts.get_base_chain(f.rel.to)
            if (chain is not None):
                for int_model in chain:
                    if (not int_opts.parents[int_model]):
                        int_opts = int_model._meta
                        continue
                    lhs_col = int_opts.parents[int_model].column
                    dedupe = (lhs_col in opts.duplicate_targets)
                    if dedupe:
                        avoid.update((self.query.dupe_avoidance.get(id(opts), lhs_col), ()))
                        dupe_set.add((opts, lhs_col))
                    int_opts = int_model._meta
                    alias = self.query.join((alias, int_opts.db_table, lhs_col, int_opts.pk.column), exclusions=used, promote=True, reuse=used)
                    alias_chain.append(alias)
                    for (dupe_opts, dupe_col) in dupe_set:
                        self.query.update_dupe_avoidance(dupe_opts, dupe_col, alias)
                dedupe = (f.column in opts.duplicate_targets)
                if (dupe_set or dedupe):
                    avoid.update(self.query.dupe_avoidance.get((id(opts), f.column), ()))
                    if dedupe:
                        dupe_set.add((opts, f.column))
            alias = self.query.join((alias, table, f.rel.get_related_field().column, f.column), exclusions=used.union(avoid), promote=True)
            used.add(alias)
            (columns, aliases) = self.get_default_columns(start_alias=alias, opts=model._meta, as_pairs=True, local_only=True)
            self.query.related_select_cols.extend(columns)
            self.query.related_select_fields.extend(model._meta.fields)
            next = requested.get(f.related_query_name(), {})
            new_nullable = True
            self.fill_related_selections(model._meta, table, (cur_depth + 1), used, next, restricted, new_nullable)
