Kaydet (Commit) a0b19a0f authored tarafından Junyi Jiao's avatar Junyi Jiao Kaydeden (comit) Tim Graham

Refs #28643 -- Added math database functions.

Thanks Nick Pope for much review.
üst 48aeca44
......@@ -173,10 +173,28 @@ class DatabaseWrapper(BaseDatabaseWrapper):
conn.create_function("django_timestamp_diff", 2, _sqlite_timestamp_diff)
conn.create_function("regexp", 2, _sqlite_regexp)
conn.create_function("django_format_dtdelta", 3, _sqlite_format_dtdelta)
conn.create_function("django_power", 2, _sqlite_power)
conn.create_function('LPAD', 3, _sqlite_lpad)
conn.create_function('REPEAT', 2, operator.mul)
conn.create_function('RPAD', 3, _sqlite_rpad)
conn.create_function('ACOS', 1, math.acos)
conn.create_function('ASIN', 1, math.asin)
conn.create_function('ATAN', 1, math.atan)
conn.create_function('ATAN2', 2, math.atan2)
conn.create_function('CEILING', 1, math.ceil)
conn.create_function('COS', 1, math.cos)
conn.create_function('COT', 1, lambda x: 1 / math.tan(x))
conn.create_function('DEGREES', 1, math.degrees)
conn.create_function('EXP', 1, math.exp)
conn.create_function('FLOOR', 1, math.floor)
conn.create_function('LN', 1, math.log)
conn.create_function('LOG', 2, lambda x, y: math.log(y, x))
conn.create_function('MOD', 2, math.fmod)
conn.create_function('PI', 0, lambda: math.pi)
conn.create_function('POWER', 2, operator.pow)
conn.create_function('RADIANS', 1, math.radians)
conn.create_function('SIN', 1, math.sin)
conn.create_function('SQRT', 1, math.sqrt)
conn.create_function('TAN', 1, math.tan)
conn.execute('PRAGMA foreign_keys = ON')
return conn
......@@ -483,7 +501,3 @@ def _sqlite_lpad(text, length, fill_text):
def _sqlite_rpad(text, length, fill_text):
return (text + fill_text * length)[:length]
def _sqlite_power(x, y):
return x ** y
......@@ -273,10 +273,10 @@ class DatabaseOperations(BaseDatabaseOperations):
)
def combine_expression(self, connector, sub_expressions):
# SQLite doesn't have a power function, so we fake it with a
# user-defined function django_power that's registered in connect().
# SQLite doesn't have a ^ operator, so use the user-defined POWER
# function that's registered in connect().
if connector == '^':
return 'django_power(%s)' % ','.join(sub_expressions)
return 'POWER(%s)' % ','.join(sub_expressions)
return super().combine_expression(connector, sub_expressions)
def combine_duration_expression(self, connector, sub_expressions):
......
......@@ -5,6 +5,10 @@ from .datetime import (
Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth,
TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear,
)
from .math import (
Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Cot, Degrees, Exp, Floor, Ln, Log,
Mod, Pi, Power, Radians, Round, Sin, Sqrt, Tan,
)
from .text import (
Chr, Concat, ConcatPair, Left, Length, Lower, LPad, LTrim, Ord, Repeat,
Replace, Right, RPad, RTrim, StrIndex, Substr, Trim, Upper,
......@@ -23,6 +27,10 @@ __all__ = [
'ExtractYear', 'Now', 'Trunc', 'TruncDate', 'TruncDay', 'TruncHour',
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
'TruncWeek', 'TruncYear',
# math
'Abs', 'ACos', 'ASin', 'ATan', 'ATan2', 'Ceil', 'Cos', 'Cot', 'Degrees',
'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round',
'Sin', 'Sqrt', 'Tan',
# text
'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'LPad', 'LTrim',
'Ord', 'Repeat', 'Replace', 'Right', 'RPad', 'RTrim', 'StrIndex', 'Substr',
......
import math
import sys
from django.db.models import (
DecimalField, FloatField, Func, IntegerField, Transform,
)
from django.db.models.functions import Cast
class DecimalInputMixin:
def as_postgresql(self, compiler, connection):
# Cast FloatField to DecimalField as PostgreSQL doesn't support the
# following function signatures:
# - LOG(double, double)
# - MOD(double, double)
output_field = DecimalField(decimal_places=sys.float_info.dig, max_digits=1000)
clone = self.copy()
clone.set_source_expressions([
Cast(expression, output_field) if isinstance(expression.output_field, FloatField)
else expression for expression in self.get_source_expressions()
])
return clone.as_sql(compiler, connection)
class OutputFieldMixin:
def _resolve_output_field(self):
has_decimals = any(isinstance(s.output_field, DecimalField) for s in self.get_source_expressions())
return DecimalField() if has_decimals else FloatField()
class Abs(Transform):
function = 'ABS'
lookup_name = 'abs'
class ACos(OutputFieldMixin, Transform):
function = 'ACOS'
lookup_name = 'acos'
class ASin(OutputFieldMixin, Transform):
function = 'ASIN'
lookup_name = 'asin'
class ATan(OutputFieldMixin, Transform):
function = 'ATAN'
lookup_name = 'atan'
class ATan2(OutputFieldMixin, Func):
function = 'ATAN2'
arity = 2
def as_sqlite(self, compiler, connection):
if not getattr(connection.ops, 'spatialite', False) or connection.ops.spatial_version < (4, 3, 0):
return self.as_sql(compiler, connection)
# This function is usually ATan2(y, x), returning the inverse tangent
# of y / x, but it's ATan2(x, y) on SpatiaLite 4.3+.
# Cast integers to float to avoid inconsistent/buggy behavior if the
# arguments are mixed between integer and float or decimal.
# https://www.gaia-gis.it/fossil/libspatialite/tktview?name=0f72cca3a2
clone = self.copy()
clone.set_source_expressions([
Cast(expression, FloatField()) if isinstance(expression.output_field, IntegerField)
else expression for expression in self.get_source_expressions()[::-1]
])
return clone.as_sql(compiler, connection)
class Ceil(Transform):
function = 'CEILING'
lookup_name = 'ceil'
def as_oracle(self, compiler, connection):
return super().as_sql(compiler, connection, function='CEIL')
class Cos(OutputFieldMixin, Transform):
function = 'COS'
lookup_name = 'cos'
class Cot(OutputFieldMixin, Transform):
function = 'COT'
lookup_name = 'cot'
def as_oracle(self, compiler, connection):
return super().as_sql(compiler, connection, template='(1 / TAN(%(expressions)s))')
class Degrees(OutputFieldMixin, Transform):
function = 'DEGREES'
lookup_name = 'degrees'
def as_oracle(self, compiler, connection):
return super().as_sql(compiler, connection, template='((%%(expressions)s) * 180 / %s)' % math.pi)
class Exp(OutputFieldMixin, Transform):
function = 'EXP'
lookup_name = 'exp'
class Floor(Transform):
function = 'FLOOR'
lookup_name = 'floor'
class Ln(OutputFieldMixin, Transform):
function = 'LN'
lookup_name = 'ln'
class Log(DecimalInputMixin, OutputFieldMixin, Func):
function = 'LOG'
arity = 2
def as_sqlite(self, compiler, connection):
if not getattr(connection.ops, 'spatialite', False):
return self.as_sql(compiler, connection)
# This function is usually Log(b, x) returning the logarithm of x to
# the base b, but on SpatiaLite it's Log(x, b).
clone = self.copy()
clone.set_source_expressions(self.get_source_expressions()[::-1])
return clone.as_sql(compiler, connection)
class Mod(DecimalInputMixin, OutputFieldMixin, Func):
function = 'MOD'
arity = 2
class Pi(OutputFieldMixin, Func):
function = 'PI'
arity = 0
def as_oracle(self, compiler, connection):
return super().as_sql(compiler, connection, template=str(math.pi))
class Power(OutputFieldMixin, Func):
function = 'POWER'
arity = 2
class Radians(OutputFieldMixin, Transform):
function = 'RADIANS'
lookup_name = 'radians'
def as_oracle(self, compiler, connection):
return super().as_sql(compiler, connection, template='((%%(expressions)s) * %s / 180)' % math.pi)
class Round(Transform):
function = 'ROUND'
lookup_name = 'round'
class Sin(OutputFieldMixin, Transform):
function = 'SIN'
lookup_name = 'sin'
class Sqrt(OutputFieldMixin, Transform):
function = 'SQRT'
lookup_name = 'sqrt'
class Tan(OutputFieldMixin, Transform):
function = 'TAN'
lookup_name = 'tan'
......@@ -166,6 +166,8 @@ Models
* Added support for PostgreSQL operator classes (:attr:`.Index.opclasses`).
* Added many :ref:`math database functions <math-functions>`.
Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~
......
......@@ -19,6 +19,7 @@ app
appname
apps
architected
arccosine
arg
args
assistive
......
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Abs
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class AbsTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-0.8'), n2=Decimal('1.2'))
obj = DecimalModel.objects.annotate(n1_abs=Abs('n1'), n2_abs=Abs('n2')).first()
self.assertIsInstance(obj.n1_abs, Decimal)
self.assertIsInstance(obj.n2_abs, Decimal)
self.assertEqual(obj.n1, -obj.n1_abs)
self.assertEqual(obj.n2, obj.n2_abs)
def test_float(self):
obj = FloatModel.objects.create(f1=-0.5, f2=12)
obj = FloatModel.objects.annotate(f1_abs=Abs('f1'), f2_abs=Abs('f2')).first()
self.assertIsInstance(obj.f1_abs, float)
self.assertIsInstance(obj.f2_abs, float)
self.assertEqual(obj.f1, -obj.f1_abs)
self.assertEqual(obj.f2, obj.f2_abs)
def test_integer(self):
IntegerModel.objects.create(small=12, normal=0, big=-45)
obj = IntegerModel.objects.annotate(
small_abs=Abs('small'),
normal_abs=Abs('normal'),
big_abs=Abs('big'),
).first()
self.assertIsInstance(obj.small_abs, int)
self.assertIsInstance(obj.normal_abs, int)
self.assertIsInstance(obj.big_abs, int)
self.assertEqual(obj.small, obj.small_abs)
self.assertEqual(obj.normal, obj.normal_abs)
self.assertEqual(obj.big, -obj.big_abs)
def test_transform(self):
try:
DecimalField.register_lookup(Abs)
DecimalModel.objects.create(n1=Decimal('-1.5'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('-0.5'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__abs__gt=1)
self.assertQuerysetEqual(objs, [Decimal('-1.5')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Abs)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import ACos
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class ACosTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-0.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_acos=ACos('n1'), n2_acos=ACos('n2')).first()
self.assertIsInstance(obj.n1_acos, Decimal)
self.assertIsInstance(obj.n2_acos, Decimal)
self.assertAlmostEqual(obj.n1_acos, Decimal(math.acos(obj.n1)))
self.assertAlmostEqual(obj.n2_acos, Decimal(math.acos(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-0.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_acos=ACos('f1'), f2_acos=ACos('f2')).first()
self.assertIsInstance(obj.f1_acos, float)
self.assertIsInstance(obj.f2_acos, float)
self.assertAlmostEqual(obj.f1_acos, math.acos(obj.f1))
self.assertAlmostEqual(obj.f2_acos, math.acos(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=0, normal=1, big=-1)
obj = IntegerModel.objects.annotate(
small_acos=ACos('small'),
normal_acos=ACos('normal'),
big_acos=ACos('big'),
).first()
self.assertIsInstance(obj.small_acos, float)
self.assertIsInstance(obj.normal_acos, float)
self.assertIsInstance(obj.big_acos, float)
self.assertAlmostEqual(obj.small_acos, math.acos(obj.small))
self.assertAlmostEqual(obj.normal_acos, math.acos(obj.normal))
self.assertAlmostEqual(obj.big_acos, math.acos(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(ACos)
DecimalModel.objects.create(n1=Decimal('0.5'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('-0.9'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__acos__lt=2)
self.assertQuerysetEqual(objs, [Decimal('0.5')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(ACos)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import ASin
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class ASinTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('0.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_asin=ASin('n1'), n2_asin=ASin('n2')).first()
self.assertIsInstance(obj.n1_asin, Decimal)
self.assertIsInstance(obj.n2_asin, Decimal)
self.assertAlmostEqual(obj.n1_asin, Decimal(math.asin(obj.n1)))
self.assertAlmostEqual(obj.n2_asin, Decimal(math.asin(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-0.5, f2=0.87)
obj = FloatModel.objects.annotate(f1_asin=ASin('f1'), f2_asin=ASin('f2')).first()
self.assertIsInstance(obj.f1_asin, float)
self.assertIsInstance(obj.f2_asin, float)
self.assertAlmostEqual(obj.f1_asin, math.asin(obj.f1))
self.assertAlmostEqual(obj.f2_asin, math.asin(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=0, normal=1, big=-1)
obj = IntegerModel.objects.annotate(
small_asin=ASin('small'),
normal_asin=ASin('normal'),
big_asin=ASin('big'),
).first()
self.assertIsInstance(obj.small_asin, float)
self.assertIsInstance(obj.normal_asin, float)
self.assertIsInstance(obj.big_asin, float)
self.assertAlmostEqual(obj.small_asin, math.asin(obj.small))
self.assertAlmostEqual(obj.normal_asin, math.asin(obj.normal))
self.assertAlmostEqual(obj.big_asin, math.asin(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(ASin)
DecimalModel.objects.create(n1=Decimal('0.1'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('1.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__asin__gt=1)
self.assertQuerysetEqual(objs, [Decimal('1.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(ASin)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import ATan
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class ATanTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_atan=ATan('n1'), n2_atan=ATan('n2')).first()
self.assertIsInstance(obj.n1_atan, Decimal)
self.assertIsInstance(obj.n2_atan, Decimal)
self.assertAlmostEqual(obj.n1_atan, Decimal(math.atan(obj.n1)))
self.assertAlmostEqual(obj.n2_atan, Decimal(math.atan(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_atan=ATan('f1'), f2_atan=ATan('f2')).first()
self.assertIsInstance(obj.f1_atan, float)
self.assertIsInstance(obj.f2_atan, float)
self.assertAlmostEqual(obj.f1_atan, math.atan(obj.f1))
self.assertAlmostEqual(obj.f2_atan, math.atan(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_atan=ATan('small'),
normal_atan=ATan('normal'),
big_atan=ATan('big'),
).first()
self.assertIsInstance(obj.small_atan, float)
self.assertIsInstance(obj.normal_atan, float)
self.assertIsInstance(obj.big_atan, float)
self.assertAlmostEqual(obj.small_atan, math.atan(obj.small))
self.assertAlmostEqual(obj.normal_atan, math.atan(obj.normal))
self.assertAlmostEqual(obj.big_atan, math.atan(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(ATan)
DecimalModel.objects.create(n1=Decimal('3.12'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('-5'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__atan__gt=0)
self.assertQuerysetEqual(objs, [Decimal('3.12')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(ATan)
import math
from decimal import Decimal
from django.db.models.functions import ATan2
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class ATan2Tests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-9.9'), n2=Decimal('4.6'))
obj = DecimalModel.objects.annotate(n_atan2=ATan2('n1', 'n2')).first()
self.assertIsInstance(obj.n_atan2, Decimal)
self.assertAlmostEqual(obj.n_atan2, Decimal(math.atan2(obj.n1, obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-25, f2=0.33)
obj = FloatModel.objects.annotate(f_atan2=ATan2('f1', 'f2')).first()
self.assertIsInstance(obj.f_atan2, float)
self.assertAlmostEqual(obj.f_atan2, math.atan2(obj.f1, obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=0, normal=1, big=10)
obj = IntegerModel.objects.annotate(
atan2_sn=ATan2('small', 'normal'),
atan2_nb=ATan2('normal', 'big'),
).first()
self.assertIsInstance(obj.atan2_sn, float)
self.assertIsInstance(obj.atan2_nb, float)
self.assertAlmostEqual(obj.atan2_sn, math.atan2(obj.small, obj.normal))
self.assertAlmostEqual(obj.atan2_nb, math.atan2(obj.normal, obj.big))
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Ceil
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class CeilTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_ceil=Ceil('n1'), n2_ceil=Ceil('n2')).first()
self.assertIsInstance(obj.n1_ceil, Decimal)
self.assertIsInstance(obj.n2_ceil, Decimal)
self.assertEqual(obj.n1_ceil, Decimal(math.ceil(obj.n1)))
self.assertEqual(obj.n2_ceil, Decimal(math.ceil(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-12.5, f2=21.33)
obj = FloatModel.objects.annotate(f1_ceil=Ceil('f1'), f2_ceil=Ceil('f2')).first()
self.assertIsInstance(obj.f1_ceil, float)
self.assertIsInstance(obj.f2_ceil, float)
self.assertEqual(obj.f1_ceil, math.ceil(obj.f1))
self.assertEqual(obj.f2_ceil, math.ceil(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-11, normal=0, big=-100)
obj = IntegerModel.objects.annotate(
small_ceil=Ceil('small'),
normal_ceil=Ceil('normal'),
big_ceil=Ceil('big'),
).first()
self.assertIsInstance(obj.small_ceil, int)
self.assertIsInstance(obj.normal_ceil, int)
self.assertIsInstance(obj.big_ceil, int)
self.assertEqual(obj.small_ceil, math.ceil(obj.small))
self.assertEqual(obj.normal_ceil, math.ceil(obj.normal))
self.assertEqual(obj.big_ceil, math.ceil(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Ceil)
DecimalModel.objects.create(n1=Decimal('3.12'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('1.25'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__ceil__gt=3)
self.assertQuerysetEqual(objs, [Decimal('3.12')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Ceil)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Cos
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class CosTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_cos=Cos('n1'), n2_cos=Cos('n2')).first()
self.assertIsInstance(obj.n1_cos, Decimal)
self.assertIsInstance(obj.n2_cos, Decimal)
self.assertAlmostEqual(obj.n1_cos, Decimal(math.cos(obj.n1)))
self.assertAlmostEqual(obj.n2_cos, Decimal(math.cos(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_cos=Cos('f1'), f2_cos=Cos('f2')).first()
self.assertIsInstance(obj.f1_cos, float)
self.assertIsInstance(obj.f2_cos, float)
self.assertAlmostEqual(obj.f1_cos, math.cos(obj.f1))
self.assertAlmostEqual(obj.f2_cos, math.cos(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_cos=Cos('small'),
normal_cos=Cos('normal'),
big_cos=Cos('big'),
).first()
self.assertIsInstance(obj.small_cos, float)
self.assertIsInstance(obj.normal_cos, float)
self.assertIsInstance(obj.big_cos, float)
self.assertAlmostEqual(obj.small_cos, math.cos(obj.small))
self.assertAlmostEqual(obj.normal_cos, math.cos(obj.normal))
self.assertAlmostEqual(obj.big_cos, math.cos(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Cos)
DecimalModel.objects.create(n1=Decimal('-8.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('3.14'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__cos__gt=-0.2)
self.assertQuerysetEqual(objs, [Decimal('-8.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Cos)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Cot
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class CotTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_cot=Cot('n1'), n2_cot=Cot('n2')).first()
self.assertIsInstance(obj.n1_cot, Decimal)
self.assertIsInstance(obj.n2_cot, Decimal)
self.assertAlmostEqual(obj.n1_cot, Decimal(1 / math.tan(obj.n1)))
self.assertAlmostEqual(obj.n2_cot, Decimal(1 / math.tan(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_cot=Cot('f1'), f2_cot=Cot('f2')).first()
self.assertIsInstance(obj.f1_cot, float)
self.assertIsInstance(obj.f2_cot, float)
self.assertAlmostEqual(obj.f1_cot, 1 / math.tan(obj.f1))
self.assertAlmostEqual(obj.f2_cot, 1 / math.tan(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-5, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_cot=Cot('small'),
normal_cot=Cot('normal'),
big_cot=Cot('big'),
).first()
self.assertIsInstance(obj.small_cot, float)
self.assertIsInstance(obj.normal_cot, float)
self.assertIsInstance(obj.big_cot, float)
self.assertAlmostEqual(obj.small_cot, 1 / math.tan(obj.small))
self.assertAlmostEqual(obj.normal_cot, 1 / math.tan(obj.normal))
self.assertAlmostEqual(obj.big_cot, 1 / math.tan(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Cot)
DecimalModel.objects.create(n1=Decimal('12.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('1.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__cot__gt=0)
self.assertQuerysetEqual(objs, [Decimal('1.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Cot)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Degrees
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class DegreesTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_degrees=Degrees('n1'), n2_degrees=Degrees('n2')).first()
self.assertIsInstance(obj.n1_degrees, Decimal)
self.assertIsInstance(obj.n2_degrees, Decimal)
self.assertAlmostEqual(obj.n1_degrees, Decimal(math.degrees(obj.n1)))
self.assertAlmostEqual(obj.n2_degrees, Decimal(math.degrees(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_degrees=Degrees('f1'), f2_degrees=Degrees('f2')).first()
self.assertIsInstance(obj.f1_degrees, float)
self.assertIsInstance(obj.f2_degrees, float)
self.assertAlmostEqual(obj.f1_degrees, math.degrees(obj.f1))
self.assertAlmostEqual(obj.f2_degrees, math.degrees(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_degrees=Degrees('small'),
normal_degrees=Degrees('normal'),
big_degrees=Degrees('big'),
).first()
self.assertIsInstance(obj.small_degrees, float)
self.assertIsInstance(obj.normal_degrees, float)
self.assertIsInstance(obj.big_degrees, float)
self.assertAlmostEqual(obj.small_degrees, math.degrees(obj.small))
self.assertAlmostEqual(obj.normal_degrees, math.degrees(obj.normal))
self.assertAlmostEqual(obj.big_degrees, math.degrees(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Degrees)
DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('-30'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__degrees__gt=0)
self.assertQuerysetEqual(objs, [Decimal('5.4')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Degrees)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Exp
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class ExpTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_exp=Exp('n1'), n2_exp=Exp('n2')).first()
self.assertIsInstance(obj.n1_exp, Decimal)
self.assertIsInstance(obj.n2_exp, Decimal)
self.assertAlmostEqual(obj.n1_exp, Decimal(math.exp(obj.n1)))
self.assertAlmostEqual(obj.n2_exp, Decimal(math.exp(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_exp=Exp('f1'), f2_exp=Exp('f2')).first()
self.assertIsInstance(obj.f1_exp, float)
self.assertIsInstance(obj.f2_exp, float)
self.assertAlmostEqual(obj.f1_exp, math.exp(obj.f1))
self.assertAlmostEqual(obj.f2_exp, math.exp(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_exp=Exp('small'),
normal_exp=Exp('normal'),
big_exp=Exp('big'),
).first()
self.assertIsInstance(obj.small_exp, float)
self.assertIsInstance(obj.normal_exp, float)
self.assertIsInstance(obj.big_exp, float)
self.assertAlmostEqual(obj.small_exp, math.exp(obj.small))
self.assertAlmostEqual(obj.normal_exp, math.exp(obj.normal))
self.assertAlmostEqual(obj.big_exp, math.exp(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Exp)
DecimalModel.objects.create(n1=Decimal('12.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('-1.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__exp__gt=10)
self.assertQuerysetEqual(objs, [Decimal('12.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Exp)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Floor
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class FloorTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_floor=Floor('n1'), n2_floor=Floor('n2')).first()
self.assertIsInstance(obj.n1_floor, Decimal)
self.assertIsInstance(obj.n2_floor, Decimal)
self.assertEqual(obj.n1_floor, Decimal(math.floor(obj.n1)))
self.assertEqual(obj.n2_floor, Decimal(math.floor(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_floor=Floor('f1'), f2_floor=Floor('f2')).first()
self.assertIsInstance(obj.f1_floor, float)
self.assertIsInstance(obj.f2_floor, float)
self.assertEqual(obj.f1_floor, math.floor(obj.f1))
self.assertEqual(obj.f2_floor, math.floor(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_floor=Floor('small'),
normal_floor=Floor('normal'),
big_floor=Floor('big'),
).first()
self.assertIsInstance(obj.small_floor, int)
self.assertIsInstance(obj.normal_floor, int)
self.assertIsInstance(obj.big_floor, int)
self.assertEqual(obj.small_floor, math.floor(obj.small))
self.assertEqual(obj.normal_floor, math.floor(obj.normal))
self.assertEqual(obj.big_floor, math.floor(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Floor)
DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('3.4'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__floor__gt=4)
self.assertQuerysetEqual(objs, [Decimal('5.4')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Floor)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Ln
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class LnTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_ln=Ln('n1'), n2_ln=Ln('n2')).first()
self.assertIsInstance(obj.n1_ln, Decimal)
self.assertIsInstance(obj.n2_ln, Decimal)
self.assertAlmostEqual(obj.n1_ln, Decimal(math.log(obj.n1)))
self.assertAlmostEqual(obj.n2_ln, Decimal(math.log(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_ln=Ln('f1'), f2_ln=Ln('f2')).first()
self.assertIsInstance(obj.f1_ln, float)
self.assertIsInstance(obj.f2_ln, float)
self.assertAlmostEqual(obj.f1_ln, math.log(obj.f1))
self.assertAlmostEqual(obj.f2_ln, math.log(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=20, normal=15, big=1)
obj = IntegerModel.objects.annotate(
small_ln=Ln('small'),
normal_ln=Ln('normal'),
big_ln=Ln('big'),
).first()
self.assertIsInstance(obj.small_ln, float)
self.assertIsInstance(obj.normal_ln, float)
self.assertIsInstance(obj.big_ln, float)
self.assertAlmostEqual(obj.small_ln, math.log(obj.small))
self.assertAlmostEqual(obj.normal_ln, math.log(obj.normal))
self.assertAlmostEqual(obj.big_ln, math.log(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Ln)
DecimalModel.objects.create(n1=Decimal('12.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('1.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__ln__gt=0)
self.assertQuerysetEqual(objs, [Decimal('12.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Ln)
import math
from decimal import Decimal
from django.db.models.functions import Log
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class LogTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('3.6'))
obj = DecimalModel.objects.annotate(n_log=Log('n1', 'n2')).first()
self.assertIsInstance(obj.n_log, Decimal)
self.assertAlmostEqual(obj.n_log, Decimal(math.log(obj.n2, obj.n1)))
def test_float(self):
FloatModel.objects.create(f1=2.0, f2=4.0)
obj = FloatModel.objects.annotate(f_log=Log('f1', 'f2')).first()
self.assertIsInstance(obj.f_log, float)
self.assertAlmostEqual(obj.f_log, math.log(obj.f2, obj.f1))
def test_integer(self):
IntegerModel.objects.create(small=4, normal=8, big=2)
obj = IntegerModel.objects.annotate(
small_log=Log('small', 'big'),
normal_log=Log('normal', 'big'),
big_log=Log('big', 'big'),
).first()
self.assertIsInstance(obj.small_log, float)
self.assertIsInstance(obj.normal_log, float)
self.assertIsInstance(obj.big_log, float)
self.assertAlmostEqual(obj.small_log, math.log(obj.big, obj.small))
self.assertAlmostEqual(obj.normal_log, math.log(obj.big, obj.normal))
self.assertAlmostEqual(obj.big_log, math.log(obj.big, obj.big))
import math
from decimal import Decimal
from django.db.models.functions import Mod
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class ModTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-9.9'), n2=Decimal('4.6'))
obj = DecimalModel.objects.annotate(n_mod=Mod('n1', 'n2')).first()
self.assertIsInstance(obj.n_mod, Decimal)
self.assertAlmostEqual(obj.n_mod, Decimal(math.fmod(obj.n1, obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-25, f2=0.33)
obj = FloatModel.objects.annotate(f_mod=Mod('f1', 'f2')).first()
self.assertIsInstance(obj.f_mod, float)
self.assertAlmostEqual(obj.f_mod, math.fmod(obj.f1, obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=20, normal=15, big=1)
obj = IntegerModel.objects.annotate(
small_mod=Mod('small', 'normal'),
normal_mod=Mod('normal', 'big'),
big_mod=Mod('big', 'small'),
).first()
self.assertIsInstance(obj.small_mod, float)
self.assertIsInstance(obj.normal_mod, float)
self.assertIsInstance(obj.big_mod, float)
self.assertEqual(obj.small_mod, math.fmod(obj.small, obj.normal))
self.assertEqual(obj.normal_mod, math.fmod(obj.normal, obj.big))
self.assertEqual(obj.big_mod, math.fmod(obj.big, obj.small))
import math
from django.db.models.functions import Pi
from django.test import TestCase
from ..models import FloatModel
class PiTests(TestCase):
def test(self):
FloatModel.objects.create(f1=2.5, f2=15.9)
obj = FloatModel.objects.annotate(pi=Pi()).first()
self.assertIsInstance(obj.pi, float)
self.assertAlmostEqual(obj.pi, math.pi, places=5)
from decimal import Decimal
from django.db.models.functions import Power
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class PowerTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('1.0'), n2=Decimal('-0.6'))
obj = DecimalModel.objects.annotate(n_power=Power('n1', 'n2')).first()
self.assertIsInstance(obj.n_power, Decimal)
self.assertAlmostEqual(obj.n_power, Decimal(obj.n1 ** obj.n2))
def test_float(self):
FloatModel.objects.create(f1=2.3, f2=1.1)
obj = FloatModel.objects.annotate(f_power=Power('f1', 'f2')).first()
self.assertIsInstance(obj.f_power, float)
self.assertAlmostEqual(obj.f_power, obj.f1 ** obj.f2)
def test_integer(self):
IntegerModel.objects.create(small=-1, normal=20, big=3)
obj = IntegerModel.objects.annotate(
small_power=Power('small', 'normal'),
normal_power=Power('normal', 'big'),
big_power=Power('big', 'small'),
).first()
self.assertIsInstance(obj.small_power, float)
self.assertIsInstance(obj.normal_power, float)
self.assertIsInstance(obj.big_power, float)
self.assertAlmostEqual(obj.small_power, obj.small ** obj.normal)
self.assertAlmostEqual(obj.normal_power, obj.normal ** obj.big)
self.assertAlmostEqual(obj.big_power, obj.big ** obj.small)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Radians
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class RadiansTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_radians=Radians('n1'), n2_radians=Radians('n2')).first()
self.assertIsInstance(obj.n1_radians, Decimal)
self.assertIsInstance(obj.n2_radians, Decimal)
self.assertAlmostEqual(obj.n1_radians, Decimal(math.radians(obj.n1)))
self.assertAlmostEqual(obj.n2_radians, Decimal(math.radians(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_radians=Radians('f1'), f2_radians=Radians('f2')).first()
self.assertIsInstance(obj.f1_radians, float)
self.assertIsInstance(obj.f2_radians, float)
self.assertAlmostEqual(obj.f1_radians, math.radians(obj.f1))
self.assertAlmostEqual(obj.f2_radians, math.radians(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_radians=Radians('small'),
normal_radians=Radians('normal'),
big_radians=Radians('big'),
).first()
self.assertIsInstance(obj.small_radians, float)
self.assertIsInstance(obj.normal_radians, float)
self.assertIsInstance(obj.big_radians, float)
self.assertAlmostEqual(obj.small_radians, math.radians(obj.small))
self.assertAlmostEqual(obj.normal_radians, math.radians(obj.normal))
self.assertAlmostEqual(obj.big_radians, math.radians(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Radians)
DecimalModel.objects.create(n1=Decimal('2.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('-1.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__radians__gt=0)
self.assertQuerysetEqual(objs, [Decimal('2.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Radians)
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Round
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class RoundTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_round=Round('n1'), n2_round=Round('n2')).first()
self.assertIsInstance(obj.n1_round, Decimal)
self.assertIsInstance(obj.n2_round, Decimal)
self.assertAlmostEqual(obj.n1_round, round(obj.n1))
self.assertAlmostEqual(obj.n2_round, round(obj.n2))
def test_float(self):
FloatModel.objects.create(f1=-27.55, f2=0.55)
obj = FloatModel.objects.annotate(f1_round=Round('f1'), f2_round=Round('f2')).first()
self.assertIsInstance(obj.f1_round, float)
self.assertIsInstance(obj.f2_round, float)
self.assertAlmostEqual(obj.f1_round, round(obj.f1))
self.assertAlmostEqual(obj.f2_round, round(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_round=Round('small'),
normal_round=Round('normal'),
big_round=Round('big'),
).first()
self.assertIsInstance(obj.small_round, int)
self.assertIsInstance(obj.normal_round, int)
self.assertIsInstance(obj.big_round, int)
self.assertEqual(obj.small_round, round(obj.small))
self.assertEqual(obj.normal_round, round(obj.normal))
self.assertEqual(obj.big_round, round(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Round)
DecimalModel.objects.create(n1=Decimal('2.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('-1.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__round__gt=0)
self.assertQuerysetEqual(objs, [Decimal('2.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Round)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Sin
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class SinTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_sin=Sin('n1'), n2_sin=Sin('n2')).first()
self.assertIsInstance(obj.n1_sin, Decimal)
self.assertIsInstance(obj.n2_sin, Decimal)
self.assertAlmostEqual(obj.n1_sin, Decimal(math.sin(obj.n1)))
self.assertAlmostEqual(obj.n2_sin, Decimal(math.sin(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_sin=Sin('f1'), f2_sin=Sin('f2')).first()
self.assertIsInstance(obj.f1_sin, float)
self.assertIsInstance(obj.f2_sin, float)
self.assertAlmostEqual(obj.f1_sin, math.sin(obj.f1))
self.assertAlmostEqual(obj.f2_sin, math.sin(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_sin=Sin('small'),
normal_sin=Sin('normal'),
big_sin=Sin('big'),
).first()
self.assertIsInstance(obj.small_sin, float)
self.assertIsInstance(obj.normal_sin, float)
self.assertIsInstance(obj.big_sin, float)
self.assertAlmostEqual(obj.small_sin, math.sin(obj.small))
self.assertAlmostEqual(obj.normal_sin, math.sin(obj.normal))
self.assertAlmostEqual(obj.big_sin, math.sin(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Sin)
DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('0.1'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__sin__lt=0)
self.assertQuerysetEqual(objs, [Decimal('5.4')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Sin)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Sqrt
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class SqrtTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_sqrt=Sqrt('n1'), n2_sqrt=Sqrt('n2')).first()
self.assertIsInstance(obj.n1_sqrt, Decimal)
self.assertIsInstance(obj.n2_sqrt, Decimal)
self.assertAlmostEqual(obj.n1_sqrt, Decimal(math.sqrt(obj.n1)))
self.assertAlmostEqual(obj.n2_sqrt, Decimal(math.sqrt(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_sqrt=Sqrt('f1'), f2_sqrt=Sqrt('f2')).first()
self.assertIsInstance(obj.f1_sqrt, float)
self.assertIsInstance(obj.f2_sqrt, float)
self.assertAlmostEqual(obj.f1_sqrt, math.sqrt(obj.f1))
self.assertAlmostEqual(obj.f2_sqrt, math.sqrt(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=20, normal=15, big=1)
obj = IntegerModel.objects.annotate(
small_sqrt=Sqrt('small'),
normal_sqrt=Sqrt('normal'),
big_sqrt=Sqrt('big'),
).first()
self.assertIsInstance(obj.small_sqrt, float)
self.assertIsInstance(obj.normal_sqrt, float)
self.assertIsInstance(obj.big_sqrt, float)
self.assertAlmostEqual(obj.small_sqrt, math.sqrt(obj.small))
self.assertAlmostEqual(obj.normal_sqrt, math.sqrt(obj.normal))
self.assertAlmostEqual(obj.big_sqrt, math.sqrt(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Sqrt)
DecimalModel.objects.create(n1=Decimal('6.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('1.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__sqrt__gt=2)
self.assertQuerysetEqual(objs, [Decimal('6.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Sqrt)
import math
from decimal import Decimal
from django.db.models import DecimalField
from django.db.models.functions import Tan
from django.test import TestCase
from ..models import DecimalModel, FloatModel, IntegerModel
class TanTests(TestCase):
def test_decimal(self):
DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6'))
obj = DecimalModel.objects.annotate(n1_tan=Tan('n1'), n2_tan=Tan('n2')).first()
self.assertIsInstance(obj.n1_tan, Decimal)
self.assertIsInstance(obj.n2_tan, Decimal)
self.assertAlmostEqual(obj.n1_tan, Decimal(math.tan(obj.n1)))
self.assertAlmostEqual(obj.n2_tan, Decimal(math.tan(obj.n2)))
def test_float(self):
FloatModel.objects.create(f1=-27.5, f2=0.33)
obj = FloatModel.objects.annotate(f1_tan=Tan('f1'), f2_tan=Tan('f2')).first()
self.assertIsInstance(obj.f1_tan, float)
self.assertIsInstance(obj.f2_tan, float)
self.assertAlmostEqual(obj.f1_tan, math.tan(obj.f1))
self.assertAlmostEqual(obj.f2_tan, math.tan(obj.f2))
def test_integer(self):
IntegerModel.objects.create(small=-20, normal=15, big=-1)
obj = IntegerModel.objects.annotate(
small_tan=Tan('small'),
normal_tan=Tan('normal'),
big_tan=Tan('big'),
).first()
self.assertIsInstance(obj.small_tan, float)
self.assertIsInstance(obj.normal_tan, float)
self.assertIsInstance(obj.big_tan, float)
self.assertAlmostEqual(obj.small_tan, math.tan(obj.small))
self.assertAlmostEqual(obj.normal_tan, math.tan(obj.normal))
self.assertAlmostEqual(obj.big_tan, math.tan(obj.big))
def test_transform(self):
try:
DecimalField.register_lookup(Tan)
DecimalModel.objects.create(n1=Decimal('0.0'), n2=Decimal('0'))
DecimalModel.objects.create(n1=Decimal('12.0'), n2=Decimal('0'))
objs = DecimalModel.objects.filter(n1__tan__lt=0)
self.assertQuerysetEqual(objs, [Decimal('12.0')], lambda a: a.n1)
finally:
DecimalField._unregister_lookup(Tan)
......@@ -54,3 +54,14 @@ class DTModel(models.Model):
class DecimalModel(models.Model):
n1 = models.DecimalField(decimal_places=2, max_digits=6)
n2 = models.DecimalField(decimal_places=2, max_digits=6)
class IntegerModel(models.Model):
big = models.BigIntegerField(null=True, blank=True)
normal = models.IntegerField(null=True, blank=True)
small = models.SmallIntegerField(null=True, blank=True)
class FloatModel(models.Model):
f1 = models.FloatField(null=True, blank=True)
f2 = models.FloatField(null=True, blank=True)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment