[1.8.x] Refs #24485 -- Renamed some expression types
Backport of 88d798d71a
from master
This commit is contained in:
parent
34e09e532d
commit
a0cebe82b5
|
@ -2,7 +2,7 @@ from django.contrib.gis import forms
|
||||||
from django.contrib.gis.db.models.lookups import gis_lookups
|
from django.contrib.gis.db.models.lookups import gis_lookups
|
||||||
from django.contrib.gis.db.models.proxy import GeometryProxy
|
from django.contrib.gis.db.models.proxy import GeometryProxy
|
||||||
from django.contrib.gis.geometry.backend import Geometry, GeometryException
|
from django.contrib.gis.geometry.backend import Geometry, GeometryException
|
||||||
from django.db.models.expressions import ExpressionNode
|
from django.db.models.expressions import Expression
|
||||||
from django.db.models.fields import Field
|
from django.db.models.fields import Field
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -188,7 +188,7 @@ class GeometryField(GeoSelectFormatMixin, Field):
|
||||||
returning to the caller.
|
returning to the caller.
|
||||||
"""
|
"""
|
||||||
value = super(GeometryField, self).get_prep_value(value)
|
value = super(GeometryField, self).get_prep_value(value)
|
||||||
if isinstance(value, ExpressionNode):
|
if isinstance(value, Expression):
|
||||||
return value
|
return value
|
||||||
elif isinstance(value, (tuple, list)):
|
elif isinstance(value, (tuple, list)):
|
||||||
geom = value[0]
|
geom = value[0]
|
||||||
|
@ -282,7 +282,7 @@ class GeometryField(GeoSelectFormatMixin, Field):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
params += value[1:]
|
params += value[1:]
|
||||||
elif isinstance(value, ExpressionNode):
|
elif isinstance(value, Expression):
|
||||||
params = []
|
params = []
|
||||||
else:
|
else:
|
||||||
params = [connection.ops.Adapter(value)]
|
params = [connection.ops.Adapter(value)]
|
||||||
|
|
|
@ -4,7 +4,7 @@ import re
|
||||||
|
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.db.models.expressions import Col, ExpressionNode
|
from django.db.models.expressions import Col, Expression
|
||||||
from django.db.models.lookups import Lookup
|
from django.db.models.lookups import Lookup
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ class GISLookup(Lookup):
|
||||||
if not hasattr(geo_fld, 'srid'):
|
if not hasattr(geo_fld, 'srid'):
|
||||||
raise ValueError('No geographic field found in expression.')
|
raise ValueError('No geographic field found in expression.')
|
||||||
self.rhs.srid = geo_fld.srid
|
self.rhs.srid = geo_fld.srid
|
||||||
elif isinstance(self.rhs, ExpressionNode):
|
elif isinstance(self.rhs, Expression):
|
||||||
raise ValueError('Complex expressions not supported for GeometryField')
|
raise ValueError('Complex expressions not supported for GeometryField')
|
||||||
elif isinstance(self.rhs, (list, tuple)):
|
elif isinstance(self.rhs, (list, tuple)):
|
||||||
geom = self.rhs[0]
|
geom = self.rhs[0]
|
||||||
|
|
|
@ -4,7 +4,7 @@ import warnings
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured # NOQA
|
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured # NOQA
|
||||||
from django.db.models.query import Q, QuerySet, Prefetch # NOQA
|
from django.db.models.query import Q, QuerySet, Prefetch # NOQA
|
||||||
from django.db.models.expressions import ExpressionNode, F, Value, Func, Case, When # NOQA
|
from django.db.models.expressions import Expression, F, Value, Func, Case, When # NOQA
|
||||||
from django.db.models.manager import Manager # NOQA
|
from django.db.models.manager import Manager # NOQA
|
||||||
from django.db.models.base import Model # NOQA
|
from django.db.models.base import Model # NOQA
|
||||||
from django.db.models.aggregates import * # NOQA
|
from django.db.models.aggregates import * # NOQA
|
||||||
|
|
|
@ -42,8 +42,8 @@ class Combinable(object):
|
||||||
other = Value(other)
|
other = Value(other)
|
||||||
|
|
||||||
if reversed:
|
if reversed:
|
||||||
return Expression(other, connector, self)
|
return CombinedExpression(other, connector, self)
|
||||||
return Expression(self, connector, other)
|
return CombinedExpression(self, connector, other)
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# OPERATORS #
|
# OPERATORS #
|
||||||
|
@ -156,8 +156,8 @@ class BaseExpression(object):
|
||||||
```
|
```
|
||||||
def override_as_sql(self, compiler, connection):
|
def override_as_sql(self, compiler, connection):
|
||||||
# custom logic
|
# custom logic
|
||||||
return super(ExpressionNode, self).as_sql(compiler, connection)
|
return super(Expression, self).as_sql(compiler, connection)
|
||||||
setattr(ExpressionNode, 'as_' + connection.vendor, override_as_sql)
|
setattr(Expression, 'as_' + connection.vendor, override_as_sql)
|
||||||
```
|
```
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
@ -193,7 +193,7 @@ class BaseExpression(object):
|
||||||
* summarize: a terminal aggregate clause
|
* summarize: a terminal aggregate clause
|
||||||
* for_save: whether this expression about to be used in a save or update
|
* for_save: whether this expression about to be used in a save or update
|
||||||
|
|
||||||
Returns: an ExpressionNode to be added to the query.
|
Returns: an Expression to be added to the query.
|
||||||
"""
|
"""
|
||||||
c = self.copy()
|
c = self.copy()
|
||||||
c.is_summary = summarize
|
c.is_summary = summarize
|
||||||
|
@ -330,17 +330,17 @@ class BaseExpression(object):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class ExpressionNode(BaseExpression, Combinable):
|
class Expression(BaseExpression, Combinable):
|
||||||
"""
|
"""
|
||||||
An expression that can be combined with other expressions.
|
An expression that can be combined with other expressions.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Expression(ExpressionNode):
|
class CombinedExpression(Expression):
|
||||||
|
|
||||||
def __init__(self, lhs, connector, rhs, output_field=None):
|
def __init__(self, lhs, connector, rhs, output_field=None):
|
||||||
super(Expression, self).__init__(output_field=output_field)
|
super(CombinedExpression, self).__init__(output_field=output_field)
|
||||||
self.connector = connector
|
self.connector = connector
|
||||||
self.lhs = lhs
|
self.lhs = lhs
|
||||||
self.rhs = rhs
|
self.rhs = rhs
|
||||||
|
@ -391,7 +391,7 @@ class Expression(ExpressionNode):
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
||||||
class DurationExpression(Expression):
|
class DurationExpression(CombinedExpression):
|
||||||
def compile(self, side, compiler, connection):
|
def compile(self, side, compiler, connection):
|
||||||
if not isinstance(side, DurationValue):
|
if not isinstance(side, DurationValue):
|
||||||
try:
|
try:
|
||||||
|
@ -447,7 +447,7 @@ class F(Combinable):
|
||||||
return OrderBy(self, descending=True)
|
return OrderBy(self, descending=True)
|
||||||
|
|
||||||
|
|
||||||
class Func(ExpressionNode):
|
class Func(Expression):
|
||||||
"""
|
"""
|
||||||
A SQL function call.
|
A SQL function call.
|
||||||
"""
|
"""
|
||||||
|
@ -504,7 +504,7 @@ class Func(ExpressionNode):
|
||||||
return copy
|
return copy
|
||||||
|
|
||||||
|
|
||||||
class Value(ExpressionNode):
|
class Value(Expression):
|
||||||
"""
|
"""
|
||||||
Represents a wrapped value as a node within an expression
|
Represents a wrapped value as a node within an expression
|
||||||
"""
|
"""
|
||||||
|
@ -557,7 +557,7 @@ class DurationValue(Value):
|
||||||
return connection.ops.date_interval_sql(self.value)
|
return connection.ops.date_interval_sql(self.value)
|
||||||
|
|
||||||
|
|
||||||
class RawSQL(ExpressionNode):
|
class RawSQL(Expression):
|
||||||
def __init__(self, sql, params, output_field=None):
|
def __init__(self, sql, params, output_field=None):
|
||||||
if output_field is None:
|
if output_field is None:
|
||||||
output_field = fields.Field()
|
output_field = fields.Field()
|
||||||
|
@ -574,7 +574,7 @@ class RawSQL(ExpressionNode):
|
||||||
return [self]
|
return [self]
|
||||||
|
|
||||||
|
|
||||||
class Random(ExpressionNode):
|
class Random(Expression):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Random, self).__init__(output_field=fields.FloatField())
|
super(Random, self).__init__(output_field=fields.FloatField())
|
||||||
|
|
||||||
|
@ -585,7 +585,7 @@ class Random(ExpressionNode):
|
||||||
return connection.ops.random_function_sql(), []
|
return connection.ops.random_function_sql(), []
|
||||||
|
|
||||||
|
|
||||||
class Col(ExpressionNode):
|
class Col(Expression):
|
||||||
def __init__(self, alias, target, output_field=None):
|
def __init__(self, alias, target, output_field=None):
|
||||||
if output_field is None:
|
if output_field is None:
|
||||||
output_field = target
|
output_field = target
|
||||||
|
@ -613,7 +613,7 @@ class Col(ExpressionNode):
|
||||||
self.target.get_db_converters(connection))
|
self.target.get_db_converters(connection))
|
||||||
|
|
||||||
|
|
||||||
class Ref(ExpressionNode):
|
class Ref(Expression):
|
||||||
"""
|
"""
|
||||||
Reference to column alias of the query. For example, Ref('sum_cost') in
|
Reference to column alias of the query. For example, Ref('sum_cost') in
|
||||||
qs.annotate(sum_cost=Sum('cost')) query.
|
qs.annotate(sum_cost=Sum('cost')) query.
|
||||||
|
@ -646,7 +646,7 @@ class Ref(ExpressionNode):
|
||||||
return [self]
|
return [self]
|
||||||
|
|
||||||
|
|
||||||
class When(ExpressionNode):
|
class When(Expression):
|
||||||
template = 'WHEN %(condition)s THEN %(result)s'
|
template = 'WHEN %(condition)s THEN %(result)s'
|
||||||
|
|
||||||
def __init__(self, condition=None, then=None, **lookups):
|
def __init__(self, condition=None, then=None, **lookups):
|
||||||
|
@ -702,7 +702,7 @@ class When(ExpressionNode):
|
||||||
return cols
|
return cols
|
||||||
|
|
||||||
|
|
||||||
class Case(ExpressionNode):
|
class Case(Expression):
|
||||||
"""
|
"""
|
||||||
An SQL searched CASE expression:
|
An SQL searched CASE expression:
|
||||||
|
|
||||||
|
@ -769,7 +769,7 @@ class Case(ExpressionNode):
|
||||||
return sql, sql_params
|
return sql, sql_params
|
||||||
|
|
||||||
|
|
||||||
class Date(ExpressionNode):
|
class Date(Expression):
|
||||||
"""
|
"""
|
||||||
Add a date selection column.
|
Add a date selection column.
|
||||||
"""
|
"""
|
||||||
|
@ -816,7 +816,7 @@ class Date(ExpressionNode):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class DateTime(ExpressionNode):
|
class DateTime(Expression):
|
||||||
"""
|
"""
|
||||||
Add a datetime selection column.
|
Add a datetime selection column.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -284,9 +284,9 @@ should define the desired ``output_field``. For example, adding an
|
||||||
arithmetic between different types, it's necessary to surround the
|
arithmetic between different types, it's necessary to surround the
|
||||||
expression in another expression::
|
expression in another expression::
|
||||||
|
|
||||||
from django.db.models import DateTimeField, ExpressionNode, F
|
from django.db.models import DateTimeField, Expression, F
|
||||||
|
|
||||||
Race.objects.annotate(finish=ExpressionNode(
|
Race.objects.annotate(finish=Expression(
|
||||||
F('start') + F('duration'), output_field=DateTimeField()))
|
F('start') + F('duration'), output_field=DateTimeField()))
|
||||||
|
|
||||||
.. versionchanged:: 1.8
|
.. versionchanged:: 1.8
|
||||||
|
@ -369,13 +369,13 @@ Expression API
|
||||||
|
|
||||||
Query expressions implement the :ref:`query expression API <query-expression>`,
|
Query expressions implement the :ref:`query expression API <query-expression>`,
|
||||||
but also expose a number of extra methods and attributes listed below. All
|
but also expose a number of extra methods and attributes listed below. All
|
||||||
query expressions must inherit from ``ExpressionNode()`` or a relevant
|
query expressions must inherit from ``Expression()`` or a relevant
|
||||||
subclass.
|
subclass.
|
||||||
|
|
||||||
When a query expression wraps another expression, it is responsible for
|
When a query expression wraps another expression, it is responsible for
|
||||||
calling the appropriate methods on the wrapped expression.
|
calling the appropriate methods on the wrapped expression.
|
||||||
|
|
||||||
.. class:: ExpressionNode
|
.. class:: Expression
|
||||||
|
|
||||||
.. attribute:: contains_aggregate
|
.. attribute:: contains_aggregate
|
||||||
|
|
||||||
|
@ -489,9 +489,9 @@ We'll start by defining the template to be used for SQL generation and
|
||||||
an ``__init__()`` method to set some attributes::
|
an ``__init__()`` method to set some attributes::
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
from django.db.models import ExpressionNode
|
from django.db.models import Expression
|
||||||
|
|
||||||
class Coalesce(ExpressionNode):
|
class Coalesce(Expression):
|
||||||
template = 'COALESCE( %(expressions)s )'
|
template = 'COALESCE( %(expressions)s )'
|
||||||
|
|
||||||
def __init__(self, expressions, output_field, **extra):
|
def __init__(self, expressions, output_field, **extra):
|
||||||
|
|
|
@ -854,7 +854,7 @@ class ReprTests(TestCase):
|
||||||
self.assertEqual(repr(Date('published', 'exact')), "Date(published, exact)")
|
self.assertEqual(repr(Date('published', 'exact')), "Date(published, exact)")
|
||||||
self.assertEqual(repr(DateTime('published', 'exact', utc)), "DateTime(published, exact, %s)" % utc)
|
self.assertEqual(repr(DateTime('published', 'exact', utc)), "DateTime(published, exact, %s)" % utc)
|
||||||
self.assertEqual(repr(F('published')), "F(published)")
|
self.assertEqual(repr(F('published')), "F(published)")
|
||||||
self.assertEqual(repr(F('cost') + F('tax')), "<Expression: F(cost) + F(tax)>")
|
self.assertEqual(repr(F('cost') + F('tax')), "<CombinedExpression: F(cost) + F(tax)>")
|
||||||
self.assertEqual(repr(Func('published', function='TO_CHAR')), "Func(F(published), function=TO_CHAR)")
|
self.assertEqual(repr(Func('published', function='TO_CHAR')), "Func(F(published), function=TO_CHAR)")
|
||||||
self.assertEqual(repr(OrderBy(Value(1))), 'OrderBy(Value(1), descending=False)')
|
self.assertEqual(repr(OrderBy(Value(1))), 'OrderBy(Value(1), descending=False)')
|
||||||
self.assertEqual(repr(Random()), "Random()")
|
self.assertEqual(repr(Random()), "Random()")
|
||||||
|
|
Loading…
Reference in New Issue