From 47379d027ba2786403969367ec9c721936a823f8 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Thu, 31 Oct 2019 20:33:16 +0100 Subject: [PATCH] Fixed #30095 -- Fixed system check for RangeField/ArrayField.choices with lists and tuples. --- django/contrib/postgres/fields/array.py | 4 ++++ django/contrib/postgres/fields/ranges.py | 4 ++++ tests/postgres_tests/test_array.py | 14 ++++++++++++++ tests/postgres_tests/test_ranges.py | 14 +++++++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py index f8ce7911efb..5f30ed1ab16 100644 --- a/django/contrib/postgres/fields/array.py +++ b/django/contrib/postgres/fields/array.py @@ -46,6 +46,10 @@ class ArrayField(CheckFieldDefaultMixin, Field): self.__dict__['model'] = model self.base_field.model = model + @classmethod + def _choices_is_value(cls, value): + return isinstance(value, (list, tuple)) or super()._choices_is_value(value) + def check(self, **kwargs): errors = super().check(**kwargs) if self.base_field.remote_field: diff --git a/django/contrib/postgres/fields/ranges.py b/django/contrib/postgres/fields/ranges.py index 953d02ac65c..c0d985afa32 100644 --- a/django/contrib/postgres/fields/ranges.py +++ b/django/contrib/postgres/fields/ranges.py @@ -60,6 +60,10 @@ class RangeField(models.Field): self.__dict__['model'] = model self.base_field.model = model + @classmethod + def _choices_is_value(cls, value): + return isinstance(value, (list, tuple)) or super()._choices_is_value(value) + def get_prep_value(self, value): if value is None: return None diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py index 379a1e9bba7..7b7793f6c17 100644 --- a/tests/postgres_tests/test_array.py +++ b/tests/postgres_tests/test_array.py @@ -592,6 +592,20 @@ class TestChecks(PostgreSQLSimpleTestCase): self.assertEqual(errors[0].id, 'postgres.E001') self.assertIn('max_length', errors[0].msg) + def test_choices_tuple_list(self): + class MyModel(PostgreSQLModel): + field = ArrayField( + models.CharField(max_length=16), + choices=[ + [ + 'Media', + [(['vinyl', 'cd'], 'Audio'), (('vhs', 'dvd'), 'Video')], + ], + (['mp3', 'mp4'], 'Digital'), + ], + ) + self.assertEqual(MyModel._meta.get_field('field').check(), []) + @unittest.skipUnless(connection.vendor == 'postgresql', "PostgreSQL specific tests") class TestMigrations(TransactionTestCase): diff --git a/tests/postgres_tests/test_ranges.py b/tests/postgres_tests/test_ranges.py index 3702221107c..b68f22112f0 100644 --- a/tests/postgres_tests/test_ranges.py +++ b/tests/postgres_tests/test_ranges.py @@ -10,7 +10,7 @@ from django.test import override_settings from django.utils import timezone from . import PostgreSQLSimpleTestCase, PostgreSQLTestCase -from .models import RangeLookupsModel, RangesModel +from .models import PostgreSQLModel, RangeLookupsModel, RangesModel try: from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange @@ -413,6 +413,18 @@ class TestSerialization(PostgreSQLSimpleTestCase): self.assertEqual(new_instance.ints, NumericRange(10, None)) +class TestChecks(PostgreSQLSimpleTestCase): + def test_choices_tuple_list(self): + class Model(PostgreSQLModel): + field = pg_fields.IntegerRangeField( + choices=[ + ['1-50', [((1, 25), '1-25'), ([26, 50], '26-50')]], + ((51, 100), '51-100'), + ], + ) + self.assertEqual(Model._meta.get_field('field').check(), []) + + class TestValidators(PostgreSQLSimpleTestCase): def test_max(self):