Refs #30446 -- Defined default output_field of text database functions.
This prevented the default behavior of BaseExpression._resolve_output_field from error'ing out when such functions accepted both expressions from mixed types (e.g. SubStr(CharField, IntegerField, IntegerField)).
This commit is contained in:
parent
0d6d4e78b1
commit
ea3beb4f5a
|
@ -1,6 +1,6 @@
|
||||||
from django.db import NotSupportedError
|
from django.db import NotSupportedError
|
||||||
from django.db.models.expressions import Func, Value
|
from django.db.models.expressions import Func, Value
|
||||||
from django.db.models.fields import IntegerField
|
from django.db.models.fields import CharField, IntegerField
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.db.models.lookups import Transform
|
from django.db.models.lookups import Transform
|
||||||
|
|
||||||
|
@ -135,6 +135,7 @@ class Concat(Func):
|
||||||
class Left(Func):
|
class Left(Func):
|
||||||
function = 'LEFT'
|
function = 'LEFT'
|
||||||
arity = 2
|
arity = 2
|
||||||
|
output_field = CharField()
|
||||||
|
|
||||||
def __init__(self, expression, length, **extra):
|
def __init__(self, expression, length, **extra):
|
||||||
"""
|
"""
|
||||||
|
@ -173,6 +174,7 @@ class Lower(Transform):
|
||||||
|
|
||||||
class LPad(BytesToCharFieldConversionMixin, Func):
|
class LPad(BytesToCharFieldConversionMixin, Func):
|
||||||
function = 'LPAD'
|
function = 'LPAD'
|
||||||
|
output_field = CharField()
|
||||||
|
|
||||||
def __init__(self, expression, length, fill_text=Value(' '), **extra):
|
def __init__(self, expression, length, fill_text=Value(' '), **extra):
|
||||||
if not hasattr(length, 'resolve_expression') and length is not None and length < 0:
|
if not hasattr(length, 'resolve_expression') and length is not None and length < 0:
|
||||||
|
@ -204,6 +206,7 @@ class Ord(Transform):
|
||||||
|
|
||||||
class Repeat(BytesToCharFieldConversionMixin, Func):
|
class Repeat(BytesToCharFieldConversionMixin, Func):
|
||||||
function = 'REPEAT'
|
function = 'REPEAT'
|
||||||
|
output_field = CharField()
|
||||||
|
|
||||||
def __init__(self, expression, number, **extra):
|
def __init__(self, expression, number, **extra):
|
||||||
if not hasattr(number, 'resolve_expression') and number is not None and number < 0:
|
if not hasattr(number, 'resolve_expression') and number is not None and number < 0:
|
||||||
|
@ -303,6 +306,7 @@ class StrIndex(Func):
|
||||||
|
|
||||||
class Substr(Func):
|
class Substr(Func):
|
||||||
function = 'SUBSTRING'
|
function = 'SUBSTRING'
|
||||||
|
output_field = CharField()
|
||||||
|
|
||||||
def __init__(self, expression, pos, length=None, **extra):
|
def __init__(self, expression, pos, length=None, **extra):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.db.models import CharField, Value
|
from django.db.models import IntegerField, Value
|
||||||
from django.db.models.functions import Left, Lower
|
from django.db.models.functions import Left, Lower
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
@ -23,5 +23,5 @@ class LeftTests(TestCase):
|
||||||
Author.objects.annotate(raises=Left('name', 0))
|
Author.objects.annotate(raises=Left('name', 0))
|
||||||
|
|
||||||
def test_expressions(self):
|
def test_expressions(self):
|
||||||
authors = Author.objects.annotate(name_part=Left('name', Value(3), output_field=CharField()))
|
authors = Author.objects.annotate(name_part=Left('name', Value(3, output_field=IntegerField())))
|
||||||
self.assertQuerysetEqual(authors.order_by('name'), ['Joh', 'Rho'], lambda a: a.name_part)
|
self.assertQuerysetEqual(authors.order_by('name'), ['Joh', 'Rho'], lambda a: a.name_part)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models import CharField, Value
|
from django.db.models import Value
|
||||||
from django.db.models.functions import Length, LPad, RPad
|
from django.db.models.functions import Length, LPad, RPad
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class PadTests(TestCase):
|
||||||
def test_combined_with_length(self):
|
def test_combined_with_length(self):
|
||||||
Author.objects.create(name='Rhonda', alias='john_smith')
|
Author.objects.create(name='Rhonda', alias='john_smith')
|
||||||
Author.objects.create(name='♥♣♠', alias='bytes')
|
Author.objects.create(name='♥♣♠', alias='bytes')
|
||||||
authors = Author.objects.annotate(filled=LPad('name', Length('alias'), output_field=CharField()))
|
authors = Author.objects.annotate(filled=LPad('name', Length('alias')))
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
authors.order_by('alias'),
|
authors.order_by('alias'),
|
||||||
[' ♥♣♠', ' Rhonda'],
|
[' ♥♣♠', ' Rhonda'],
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models import CharField, Value
|
from django.db.models import Value
|
||||||
from django.db.models.functions import Length, Repeat
|
from django.db.models.functions import Length, Repeat
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ class RepeatTests(TestCase):
|
||||||
tests = (
|
tests = (
|
||||||
(Repeat('name', 0), ''),
|
(Repeat('name', 0), ''),
|
||||||
(Repeat('name', 2), 'JohnJohn'),
|
(Repeat('name', 2), 'JohnJohn'),
|
||||||
(Repeat('name', Length('alias'), output_field=CharField()), 'JohnJohnJohn'),
|
(Repeat('name', Length('alias')), 'JohnJohnJohn'),
|
||||||
(Repeat(Value('x'), 3, output_field=CharField()), 'xxx'),
|
(Repeat(Value('x'), 3), 'xxx'),
|
||||||
(Repeat('name', None), none_value),
|
(Repeat('name', None), none_value),
|
||||||
(Repeat('goes_by', 1), none_value),
|
(Repeat('goes_by', 1), none_value),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.db.models import CharField, Value
|
from django.db.models import IntegerField, Value
|
||||||
from django.db.models.functions import Lower, Right
|
from django.db.models.functions import Lower, Right
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
@ -23,5 +23,5 @@ class RightTests(TestCase):
|
||||||
Author.objects.annotate(raises=Right('name', 0))
|
Author.objects.annotate(raises=Right('name', 0))
|
||||||
|
|
||||||
def test_expressions(self):
|
def test_expressions(self):
|
||||||
authors = Author.objects.annotate(name_part=Right('name', Value(3), output_field=CharField()))
|
authors = Author.objects.annotate(name_part=Right('name', Value(3, output_field=IntegerField())))
|
||||||
self.assertQuerysetEqual(authors.order_by('name'), ['ith', 'nda'], lambda a: a.name_part)
|
self.assertQuerysetEqual(authors.order_by('name'), ['ith', 'nda'], lambda a: a.name_part)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.db.models import CharField, Value as V
|
from django.db.models import Value as V
|
||||||
from django.db.models.functions import Lower, StrIndex, Substr, Upper
|
from django.db.models.functions import Lower, StrIndex, Substr, Upper
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class SubstrTests(TestCase):
|
||||||
def test_expressions(self):
|
def test_expressions(self):
|
||||||
Author.objects.create(name='John Smith', alias='smithj')
|
Author.objects.create(name='John Smith', alias='smithj')
|
||||||
Author.objects.create(name='Rhonda')
|
Author.objects.create(name='Rhonda')
|
||||||
substr = Substr(Upper('name'), StrIndex('name', V('h')), 5, output_field=CharField())
|
substr = Substr(Upper('name'), StrIndex('name', V('h')), 5)
|
||||||
authors = Author.objects.annotate(name_part=substr)
|
authors = Author.objects.annotate(name_part=substr)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
authors.order_by('name'), ['HN SM', 'HONDA'],
|
authors.order_by('name'), ['HN SM', 'HONDA'],
|
||||||
|
|
Loading…
Reference in New Issue