summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2015-09-01 10:15:59 -0400
committerTim Graham <timograham@gmail.com>2015-09-23 19:31:10 -0400
commitfd6a299cd06fac615ccb9006df0dd98cd8461cc5 (patch)
treec2a19b2eafd05e786be4d861e389c347a7bc3d9a
parent7140d4adf724347aceda1cec7d194f0403fba027 (diff)
Refs #14030 -- Removed backwards compatiblity for old-style aggregates.
Per deprecation timeline.
-rw-r--r--django/contrib/gis/db/models/sql/aggregates.py10
-rw-r--r--django/db/models/sql/aggregates.py155
-rw-r--r--django/db/models/sql/query.py34
-rw-r--r--tests/aggregation/tests.py27
4 files changed, 3 insertions, 223 deletions
diff --git a/django/contrib/gis/db/models/sql/aggregates.py b/django/contrib/gis/db/models/sql/aggregates.py
deleted file mode 100644
index e3fb049cf5..0000000000
--- a/django/contrib/gis/db/models/sql/aggregates.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.db.models.sql import aggregates
-from django.db.models.sql.aggregates import * # NOQA
-
-__all__ = ['Collect', 'Extent', 'Extent3D', 'MakeLine', 'Union'] + aggregates.__all__
-
-
-warnings.warn(
- "django.contrib.gis.db.models.sql.aggregates is deprecated. Use "
- "django.contrib.gis.db.models.aggregates instead.",
- RemovedInDjango110Warning, stacklevel=2)
diff --git a/django/db/models/sql/aggregates.py b/django/db/models/sql/aggregates.py
deleted file mode 100644
index 4f74a3b0c0..0000000000
--- a/django/db/models/sql/aggregates.py
+++ /dev/null
@@ -1,155 +0,0 @@
-"""
-Classes to represent the default SQL aggregate functions
-"""
-import copy
-import warnings
-
-from django.db.models.fields import FloatField, IntegerField
-from django.db.models.query_utils import RegisterLookupMixin
-from django.utils.deprecation import RemovedInDjango110Warning
-from django.utils.functional import cached_property
-
-__all__ = ['Aggregate', 'Avg', 'Count', 'Max', 'Min', 'StdDev', 'Sum', 'Variance']
-
-
-warnings.warn(
- "django.db.models.sql.aggregates is deprecated. Use "
- "django.db.models.aggregates instead.",
- RemovedInDjango110Warning, stacklevel=2)
-
-
-class Aggregate(RegisterLookupMixin):
- """
- Default SQL Aggregate.
- """
- is_ordinal = False
- is_computed = False
- sql_template = '%(function)s(%(field)s)'
-
- def __init__(self, col, source=None, is_summary=False, **extra):
- """Instantiate an SQL aggregate
-
- * col is a column reference describing the subject field
- of the aggregate. It can be an alias, or a tuple describing
- a table and column name.
- * source is the underlying field or aggregate definition for
- the column reference. If the aggregate is not an ordinal or
- computed type, this reference is used to determine the coerced
- output type of the aggregate.
- * extra is a dictionary of additional data to provide for the
- aggregate definition
-
- Also utilizes the class variables:
- * sql_function, the name of the SQL function that implements the
- aggregate.
- * sql_template, a template string that is used to render the
- aggregate into SQL.
- * is_ordinal, a boolean indicating if the output of this aggregate
- is an integer (e.g., a count)
- * is_computed, a boolean indicating if this output of this aggregate
- is a computed float (e.g., an average), regardless of the input
- type.
- """
- self.col = col
- self.source = source
- self.is_summary = is_summary
- self.extra = extra
-
- # Follow the chain of aggregate sources back until you find an
- # actual field, or an aggregate that forces a particular output
- # type. This type of this field will be used to coerce values
- # retrieved from the database.
- tmp = self
-
- while tmp and isinstance(tmp, Aggregate):
- if getattr(tmp, 'is_ordinal', False):
- tmp = self._ordinal_aggregate_field
- elif getattr(tmp, 'is_computed', False):
- tmp = self._computed_aggregate_field
- else:
- tmp = tmp.source
-
- self.field = tmp
-
- # Two fake fields used to identify aggregate types in data-conversion operations.
- @cached_property
- def _ordinal_aggregate_field(self):
- return IntegerField()
-
- @cached_property
- def _computed_aggregate_field(self):
- return FloatField()
-
- def relabeled_clone(self, change_map):
- clone = copy.copy(self)
- if isinstance(self.col, (list, tuple)):
- clone.col = (change_map.get(self.col[0], self.col[0]), self.col[1])
- return clone
-
- def as_sql(self, compiler, connection):
- "Return the aggregate, rendered as SQL with parameters."
- params = []
-
- if hasattr(self.col, 'as_sql'):
- field_name, params = self.col.as_sql(compiler, connection)
- elif isinstance(self.col, (list, tuple)):
- field_name = '.'.join(compiler(c) for c in self.col)
- else:
- field_name = compiler(self.col)
-
- substitutions = {
- 'function': self.sql_function,
- 'field': field_name
- }
- substitutions.update(self.extra)
-
- return self.sql_template % substitutions, params
-
- def get_group_by_cols(self):
- return []
-
- @property
- def output_field(self):
- return self.field
-
-
-class Avg(Aggregate):
- is_computed = True
- sql_function = 'AVG'
-
-
-class Count(Aggregate):
- is_ordinal = True
- sql_function = 'COUNT'
- sql_template = '%(function)s(%(distinct)s%(field)s)'
-
- def __init__(self, col, distinct=False, **extra):
- super(Count, self).__init__(col, distinct='DISTINCT ' if distinct else '', **extra)
-
-
-class Max(Aggregate):
- sql_function = 'MAX'
-
-
-class Min(Aggregate):
- sql_function = 'MIN'
-
-
-class StdDev(Aggregate):
- is_computed = True
-
- def __init__(self, col, sample=False, **extra):
- super(StdDev, self).__init__(col, **extra)
- self.sql_function = 'STDDEV_SAMP' if sample else 'STDDEV_POP'
-
-
-class Sum(Aggregate):
- sql_function = 'SUM'
-
-
-class Variance(Aggregate):
- is_computed = True
-
- def __init__(self, col, sample=False, **extra):
- super(Variance, self).__init__(col, **extra)
- self.sql_function = 'VAR_SAMP' if sample else 'VAR_POP'
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 9dd666040f..cb1696dd62 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -7,7 +7,6 @@ databases). The abstraction barrier only works one way: this module has to know
all about the internals of models in order to get the information it needs.
"""
import copy
-import warnings
from collections import Counter, Iterator, Mapping, OrderedDict
from itertools import chain, count, product
from string import ascii_uppercase
@@ -31,7 +30,6 @@ from django.db.models.sql.where import (
AND, OR, ExtraWhere, NothingNode, WhereNode,
)
from django.utils import six
-from django.utils.deprecation import RemovedInDjango110Warning
from django.utils.encoding import force_text
from django.utils.tree import Node
@@ -214,13 +212,6 @@ class Query(object):
self._annotations = OrderedDict()
return self._annotations
- @property
- def aggregates(self):
- warnings.warn(
- "The aggregates property is deprecated. Use annotations instead.",
- RemovedInDjango110Warning, stacklevel=2)
- return self.annotations
-
def __str__(self):
"""
Returns the query as a string of SQL with the parameter values
@@ -973,12 +964,6 @@ class Query(object):
alias = seen[int_model] = joins[-1]
return alias or seen[None]
- def add_aggregate(self, aggregate, model, alias, is_summary):
- warnings.warn(
- "add_aggregate() is deprecated. Use add_annotation() instead.",
- RemovedInDjango110Warning, stacklevel=2)
- self.add_annotation(aggregate, alias, is_summary)
-
def add_annotation(self, annotation, alias, is_summary=False):
"""
Adds a single annotation expression to the Query
@@ -1818,12 +1803,6 @@ class Query(object):
"""
target[model] = {f.attname for f in fields}
- def set_aggregate_mask(self, names):
- warnings.warn(
- "set_aggregate_mask() is deprecated. Use set_annotation_mask() instead.",
- RemovedInDjango110Warning, stacklevel=2)
- self.set_annotation_mask(names)
-
def set_annotation_mask(self, names):
"Set the mask of annotations that will actually be returned by the SELECT"
if names is None:
@@ -1832,12 +1811,6 @@ class Query(object):
self.annotation_select_mask = set(names)
self._annotation_select_cache = None
- def append_aggregate_mask(self, names):
- warnings.warn(
- "append_aggregate_mask() is deprecated. Use append_annotation_mask() instead.",
- RemovedInDjango110Warning, stacklevel=2)
- self.append_annotation_mask(names)
-
def append_annotation_mask(self, names):
if self.annotation_select_mask is not None:
self.set_annotation_mask(set(names).union(self.annotation_select_mask))
@@ -1875,13 +1848,6 @@ class Query(object):
return self.annotations
@property
- def aggregate_select(self):
- warnings.warn(
- "aggregate_select() is deprecated. Use annotation_select() instead.",
- RemovedInDjango110Warning, stacklevel=2)
- return self.annotation_select
-
- @property
def extra_select(self):
if self._extra_select_cache is not None:
return self._extra_select_cache
diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py
index a1d12e363e..3fa36bbcb5 100644
--- a/tests/aggregation/tests.py
+++ b/tests/aggregation/tests.py
@@ -7,13 +7,12 @@ from decimal import Decimal
from django.core.exceptions import FieldError
from django.db import connection
from django.db.models import (
- F, Aggregate, Avg, Count, DecimalField, DurationField, FloatField, Func,
- IntegerField, Max, Min, Sum, Value,
+ F, Avg, Count, DecimalField, DurationField, FloatField, Func, IntegerField,
+ Max, Min, Sum, Value,
)
-from django.test import TestCase, ignore_warnings
+from django.test import TestCase
from django.test.utils import Approximate, CaptureQueriesContext
from django.utils import six, timezone
-from django.utils.deprecation import RemovedInDjango110Warning
from .models import Author, Book, Publisher, Store
@@ -1184,23 +1183,3 @@ class AggregateTestCase(TestCase):
).filter(rating_or_num_awards__gt=F('num_awards')).order_by('num_awards')
self.assertQuerysetEqual(
qs2, [1, 3], lambda v: v.num_awards)
-
- @ignore_warnings(category=RemovedInDjango110Warning)
- def test_backwards_compatibility(self):
- from django.db.models.sql import aggregates as sql_aggregates
-
- class SqlNewSum(sql_aggregates.Aggregate):
- sql_function = 'SUM'
-
- class NewSum(Aggregate):
- name = 'Sum'
-
- def add_to_query(self, query, alias, col, source, is_summary):
- klass = SqlNewSum
- aggregate = klass(
- col, source=source, is_summary=is_summary, **self.extra)
- query.annotations[alias] = aggregate
-
- qs = Author.objects.values('name').annotate(another_age=NewSum('age') + F('age'))
- a = qs.get(name="Adrian Holovaty")
- self.assertEqual(a['another_age'], 68)