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:
Simon Charette 2020-06-16 10:01:34 +02:00 committed by Mariusz Felisiak
parent 0d6d4e78b1
commit ea3beb4f5a
6 changed files with 16 additions and 12 deletions

View File

@ -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):
""" """

View File

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

View File

@ -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'],

View File

@ -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),
) )

View File

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

View File

@ -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'],