예제 #1
0
파일: compiler.py 프로젝트: zeroos/django
    def fill_related_selections(self,
                                opts=None,
                                root_alias=None,
                                cur_depth=1,
                                requested=None,
                                restricted=None,
                                nullable=None):
        """
        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).
        """
        if not restricted and self.query.max_depth and cur_depth > self.query.max_depth:
            # We've recursed far enough; bail out.
            return

        if not opts:
            opts = self.query.get_meta()
            root_alias = self.query.get_initial_alias()
            self.query.related_select_cols = []
        only_load = self.query.get_loaded_field_names()

        # Setup for the case when only particular related fields should be
        # included in the related selection.
        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():
            # The get_fields_with_model() returns None for fields that live
            # in the field's local model. So, for those fields we want to use
            # the f.model - that is the field's local model.
            field_model = model or f.model
            if not select_related_descend(f, restricted, requested,
                                          only_load.get(field_model)):
                continue
            table = f.rel.to._meta.db_table
            promote = nullable or f.null
            alias = self.query.join_parent_model(opts, model, root_alias, {})
            join_cols = f.get_joining_columns()
            alias = self.query.join((alias, table, join_cols),
                                    outer_if_first=promote,
                                    join_field=f)
            columns, aliases = self.get_default_columns(start_alias=alias,
                                                        opts=f.rel.to._meta,
                                                        as_pairs=True)
            self.query.related_select_cols.extend(
                SelectInfo(col, field)
                for col, field in zip(columns, f.rel.to._meta.concrete_fields))
            if restricted:
                next = requested.get(f.name, {})
            else:
                next = False
            new_nullable = f.null or promote
            self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
                                         next, restricted, new_nullable)

        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

                alias = self.query.join_parent_model(opts, f.rel.to,
                                                     root_alias, {})
                table = model._meta.db_table
                alias = self.query.join(
                    (alias, table, f.get_joining_columns(reverse_join=True)),
                    outer_if_first=True,
                    join_field=f)
                from_parent = (opts.model
                               if issubclass(model, opts.model) else None)
                columns, aliases = self.get_default_columns(
                    start_alias=alias,
                    opts=model._meta,
                    as_pairs=True,
                    from_parent=from_parent)
                self.query.related_select_cols.extend(
                    SelectInfo(col, field) for col, field in zip(
                        columns, model._meta.concrete_fields))
                next = requested.get(f.related_query_name(), {})
                # Use True here because we are looking at the _reverse_ side of
                # the relation, which is always nullable.
                new_nullable = True

                self.fill_related_selections(model._meta, table, cur_depth + 1,
                                             next, restricted, new_nullable)
예제 #2
0
    def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
            requested=None, restricted=None):
        """
        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).
        """
        if not restricted and self.query.max_depth and cur_depth > self.query.max_depth:
            # We've recursed far enough; bail out.
            return

        if not opts:
            opts = self.query.get_meta()
            root_alias = self.query.get_initial_alias()
            self.query.related_select_cols = []
        only_load = self.query.get_loaded_field_names()

        # Setup for the case when only particular related fields should be
        # included in the related selection.
        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():
            # The get_fields_with_model() returns None for fields that live
            # in the field's local model. So, for those fields we want to use
            # the f.model - that is the field's local model.
            field_model = model or f.model
            if not select_related_descend(f, restricted, requested,
                                          only_load.get(field_model)):
                continue
            _, _, _, joins, _ = self.query.setup_joins(
                [f.name], opts, root_alias)
            alias = joins[-1]
            columns, _ = self.get_default_columns(start_alias=alias,
                    opts=f.rel.to._meta, as_pairs=True)
            self.query.related_select_cols.extend(
                SelectInfo((col[0], col[1].column), col[1]) for col in columns)
            if restricted:
                next = requested.get(f.name, {})
            else:
                next = False
            self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
                    next, restricted)

        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

                _, _, _, joins, _ = self.query.setup_joins(
                    [f.related_query_name()], opts, root_alias)
                alias = joins[-1]
                from_parent = (opts.model if issubclass(model, opts.model)
                               else None)
                columns, _ = self.get_default_columns(start_alias=alias,
                    opts=model._meta, as_pairs=True, from_parent=from_parent)
                self.query.related_select_cols.extend(
                    SelectInfo((col[0], col[1].column), col[1]) for col in columns)
                next = requested.get(f.related_query_name(), {})
                self.fill_related_selections(model._meta, alias, cur_depth + 1,
                                             next, restricted)
예제 #3
0
파일: compiler.py 프로젝트: zoori/django
    def fill_related_selections(self,
                                opts=None,
                                root_alias=None,
                                cur_depth=1,
                                requested=None,
                                restricted=None,
                                nullable=None):
        """
        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).
        """
        if not restricted and self.query.max_depth and cur_depth > self.query.max_depth:
            # We've recursed far enough; bail out.
            return

        if not opts:
            opts = self.query.get_meta()
            root_alias = self.query.get_initial_alias()
            self.query.related_select_cols = []
        only_load = self.query.get_loaded_field_names()

        # Setup for the case when only particular related fields should be
        # included in the related selection.
        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():
            # The get_fields_with_model() returns None for fields that live
            # in the field's local model. So, for those fields we want to use
            # the f.model - that is the field's local model.
            field_model = model or f.model
            if not select_related_descend(f, restricted, requested,
                                          only_load.get(field_model)):
                continue
            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):
                    # Proxy model have elements in base chain
                    # with no parents, assign the new options
                    # object and skip to the next base in that
                    # case
                    if not int_opts.parents[int_model]:
                        int_opts = int_model._meta
                        continue
                    lhs_col = int_opts.parents[int_model].column
                    int_opts = int_model._meta
                    alias = self.query.join((alias, int_opts.db_table, lhs_col,
                                             int_opts.pk.column),
                                            promote=promote)
                    alias_chain.append(alias)
            else:
                alias = root_alias

            alias = self.query.join(
                (alias, table, f.column, f.rel.get_related_field().column),
                promote=promote)
            columns, aliases = self.get_default_columns(start_alias=alias,
                                                        opts=f.rel.to._meta,
                                                        as_pairs=True)
            self.query.related_select_cols.extend(
                SelectInfo(col, field)
                for col, field in zip(columns, f.rel.to._meta.fields))
            if restricted:
                next = requested.get(f.name, {})
            else:
                next = False
            new_nullable = f.null or promote
            self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
                                         next, restricted, new_nullable)

        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

                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:
                        # Proxy model have elements in base chain
                        # with no parents, assign the new options
                        # object and skip to the next base in that
                        # case
                        if not int_opts.parents[int_model]:
                            int_opts = int_model._meta
                            continue
                        lhs_col = int_opts.parents[int_model].column
                        int_opts = int_model._meta
                        alias = self.query.join(
                            (alias, int_opts.db_table, lhs_col,
                             int_opts.pk.column),
                            promote=True,
                        )
                        alias_chain.append(alias)
                alias = self.query.join(
                    (alias, table, f.rel.get_related_field().column, f.column),
                    promote=True)
                from_parent = (opts.model
                               if issubclass(model, opts.model) else None)
                columns, aliases = self.get_default_columns(
                    start_alias=alias,
                    opts=model._meta,
                    as_pairs=True,
                    from_parent=from_parent)
                self.query.related_select_cols.extend(
                    SelectInfo(col, field)
                    for col, field in zip(columns, model._meta.fields))
                next = requested.get(f.related_query_name(), {})
                # Use True here because we are looking at the _reverse_ side of
                # the relation, which is always nullable.
                new_nullable = True

                self.fill_related_selections(model._meta, table, cur_depth + 1,
                                             next, restricted, new_nullable)