Fixed #28371 -- Fixed Cast() with CharField if the max_length argument isn't provided.

Thanks Tim Graham for the review.
This commit is contained in:
Mariusz Felisiak 2017-07-27 19:36:47 +02:00 committed by GitHub
parent 14172cf442
commit b61d5b1991
8 changed files with 25 additions and 0 deletions

View File

@ -36,6 +36,8 @@ class BaseDatabaseOperations:
# name) to the data type to use for the Cast() function, if different from
# DatabaseWrapper.data_types.
cast_data_types = {}
# CharField data type if the max_length argument isn't provided.
cast_char_field_without_max_length = None
def __init__(self, connection):
self.connection = connection

View File

@ -24,6 +24,7 @@ class DatabaseOperations(BaseDatabaseOperations):
'PositiveIntegerField': 'unsigned integer',
'PositiveSmallIntegerField': 'unsigned integer',
}
cast_char_field_without_max_length = 'char'
def date_extract_sql(self, lookup_type, field_name):
# http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html

View File

@ -49,6 +49,9 @@ BEGIN
END;
/"""
# Oracle doesn't support string without precision; use the max string size.
cast_char_field_without_max_length = 'NVARCHAR2(2000)'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_operators['difference'] = 'MINUS'

View File

@ -5,6 +5,8 @@ from django.db.backends.base.operations import BaseDatabaseOperations
class DatabaseOperations(BaseDatabaseOperations):
cast_char_field_without_max_length = 'varchar'
def unification_cast_sql(self, output_field):
internal_type = output_field.get_internal_type()
if internal_type in ("GenericIPAddressField", "IPAddressField", "TimeField", "UUIDField"):

View File

@ -14,6 +14,8 @@ from django.utils.duration import duration_string
class DatabaseOperations(BaseDatabaseOperations):
cast_char_field_without_max_length = 'text'
def bulk_batch_size(self, fields, objs):
"""
SQLite has a compile-time default (SQLITE_LIMIT_VARIABLE_NUMBER) of

View File

@ -1066,6 +1066,11 @@ class CharField(Field):
else:
return []
def cast_db_type(self, connection):
if self.max_length is None:
return connection.ops.cast_char_field_without_max_length
return super().cast_db_type(connection)
def get_internal_type(self):
return "CharField"

View File

@ -348,6 +348,12 @@ backends.
requires that the arguments to ``OF`` be columns rather than tables, set
``DatabaseFeatures.select_for_update_of_column = True``.
* Third-party database backends should add a
``DatabaseOperations.cast_char_field_without_max_length`` attribute with the
database data type that will be used in the
:class:`~django.db.models.functions.Cast` function for a ``CharField`` if the
``max_length`` argument isn't provided.
Dropped support for Oracle 11.2
-------------------------------

View File

@ -19,6 +19,10 @@ class CastTests(TestCase):
numbers = Author.objects.annotate(cast_string=Cast('age', models.CharField(max_length=255)),)
self.assertEqual(numbers.get().cast_string, '1')
def test_cast_to_char_field_without_max_length(self):
numbers = Author.objects.annotate(cast_string=Cast('age', models.CharField()))
self.assertEqual(numbers.get().cast_string, '1')
# Silence "Truncated incorrect CHAR(1) value: 'Bob'".
@ignore_warnings(module='django.db.backends.mysql.base')
@skipUnlessDBFeature('supports_cast_with_precision')