Ejemplo n.º 1
0
    def add_select(self, field_name, lookup_type, order='ASC'):
        """
        Converts the query into an extraction query.
        """
        try:
            result = self.setup_joins(
                field_name.split(LOOKUP_SEP),
                self.get_meta(),
                self.get_initial_alias(),
            )
        except FieldError:
            raise FieldDoesNotExist("%s has no field named '%s'" % (
                self.get_meta().object_name, field_name
            ))
        field = result[0]
        self._check_field(field)                # overridden in DateTimeQuery
        alias = result[3][-1]
        select = self._get_select((alias, field.column), lookup_type)
        self.clear_select_clause()
        self.select = [SelectInfo(select, None)]
        self.distinct = True
        self.order_by = [1] if order == 'ASC' else [-1]

        if field.null:
            self.add_filter(("%s__isnull" % field_name, False))
Ejemplo n.º 2
0
def add_fields(self, field_names, allow_m2m=True):
    """
    Adds the given (model) fields to the select set. The field names are
    added in the order specified.
    """
    alias = self.get_initial_alias()
    opts = self.get_meta()

    try:
        for name in field_names:
            field, targets, u2, joins, path = self.setup_joins(
                name.split(LOOKUP_SEP),
                opts,
                alias,
                None,
                allow_m2m,
                allow_explicit_fk=True,
                outer_if_first=True)

            # Trim last join if possible
            targets, final_alias, remaining_joins = self.trim_joins(
                targets, joins[-2:], path)
            joins = joins[:-2] + remaining_joins

            self.promote_joins(joins[1:])
            for target in targets:
                col = target.column
                cols = [] if hasattr(col, "columns") else [col]
                for col in cols:
                    print "select", final_alias, col, target
                    self.select.append(SelectInfo((final_alias, col), target))
    except MultiJoin:
        raise FieldError("Invalid field name: '%s'" % name)
    except FieldError:
        if LOOKUP_SEP in name:
            # For lookups spanning over relationships, show the error
            # from the model on which the lookup failed.
            raise
        else:
            names = sorted(opts.get_all_field_names() + list(self.extra) +
                           list(self.aggregate_select))
            raise FieldError("Cannot resolve keyword %r into field. "
                             "Choices are: %s" % (name, ", ".join(names)))
    self.remove_inherited_models()
Ejemplo n.º 3
0
def date_aggregation(date_qs):
    """
    Performs an aggregation for a supplied DateQuerySet
    """
    # The DateQuerySet gives us a query that we need to clone and hack
    date_q = date_qs.query.clone()
    date_q.distinct = False

    # Replace 'select' to add an alias
    date_obj = date_q.select[0]

    # If it is django 1.6 generates new SelectInfo object
    if SelectInfo and isinstance(date_obj, SelectInfo):
        date_q.select = [SelectInfo(col=DateWithAlias(date_obj.col.col, date_obj.col.lookup_type), field=None)]
    else:
        date_q.select = [DateWithAlias(date_obj.col, date_obj.lookup_type)]

    # Now use as a subquery to do aggregation
    query = DateAggregateQuery(date_qs.model)
    query.add_subquery(date_q, date_qs.db)
    return query.get_counts(date_qs.db)
Ejemplo n.º 4
0
 def delete_qs(self, query, using):
     """
     Delete the queryset in one SQL query (if possible). For simple queries
     this is done by copying the query.query.where to self.query, for
     complex queries by using subquery.
     """
     innerq = query.query
     # Make sure the inner query has at least one table in use.
     innerq.get_initial_alias()
     # The same for our new query.
     self.get_initial_alias()
     innerq_used_tables = [
         t for t in innerq.tables if innerq.alias_refcount[t]
     ]
     if ((not innerq_used_tables or innerq_used_tables == self.tables)
             and not len(innerq.having)):
         # There is only the base table in use in the query, and there are
         # no aggregate filtering going on.
         self.where = innerq.where
     else:
         pk = query.model._meta.pk
         if not connections[using].features.update_can_self_select:
             # We can't do the delete using subquery.
             values = list(query.values_list('pk', flat=True))
             if not values:
                 return
             self.delete_batch(values, using)
             return
         else:
             innerq.clear_select_clause()
             innerq.select = [
                 SelectInfo((self.get_initial_alias(), pk.column), None)
             ]
             values = innerq
         where = self.where_class()
         where.add((Constraint(None, pk.column, pk), 'in', values), AND)
         self.where = where
     self.get_compiler(using).execute_sql(None)
Ejemplo n.º 5
0
def numeric_range_counts(qs, fieldname, ranges):
    # Build the query:
    query = qs.values_list(fieldname).query.clone()

    select_obj = query.select[0]
    if SelectInfo and isinstance(select_obj, SelectInfo):
        query.select = [SelectInfo(col=NumericValueRange(select_obj, ranges), field=None)]
    else:
        query.select[0] = NumericValueRange(select_obj, ranges)

    agg_query = NumericAggregateQuery(qs.model)
    agg_query.add_subquery(query, qs.db)
    results = agg_query.get_counts(qs.db)

    count_dict = SortedDict()
    for val, count in results:
        try:
            r = ranges[val]
        except IndexError:
            # Include in the top range - this could be a rounding error
            r = ranges[-1]
        count_dict[r] = count
    return count_dict
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
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)
Ejemplo n.º 8
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).
        """
        def _get_field_choices():
            direct_choices = (f.name for (f, _) in opts.get_fields_with_model() if f.rel)
            reverse_choices = (
                f.field.related_query_name()
                for f in opts.get_all_related_objects() if f.field.unique
            )
            return chain(direct_choices, reverse_choices)

        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.
        fields_found = set()
        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():
            fields_found.add(f.name)

            if restricted:
                next = requested.get(f.name, {})
                if not f.rel:
                    # If a non-related field is used like a relation,
                    # or if a single non-relational field is given.
                    if next or (cur_depth == 1 and 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

            # 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
            )
            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

                related_field_name = f.related_query_name()
                fields_found.add(related_field_name)

                _, _, _, joins, _ = self.query.setup_joins([related_field_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)

            fields_not_found = set(requested.keys()).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)',
                    )
                )
Ejemplo n.º 9
0
    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
                )
                columns, aliases = self.get_default_columns(start_alias=alias,
                    opts=model._meta, as_pairs=True, local_only=True)
                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)