Fixed #20430 - Enable iterable of iterables for model choices
Allows for any iterable, not just lists or tuples, to be used as the inner item for a list of choices in a model.
This commit is contained in:
parent
a0c0cc924e
commit
a19e9d80ff
|
@ -118,8 +118,8 @@ def get_validation_errors(outfile, app=None):
|
||||||
e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
|
e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
|
||||||
else:
|
else:
|
||||||
for c in f.choices:
|
for c in f.choices:
|
||||||
if not isinstance(c, (list, tuple)) or len(c) != 2:
|
if isinstance(c, six.string_types) or not is_iterable(c) or len(c) != 2:
|
||||||
e.add(opts, '"%s": "choices" should be a sequence of two-tuples.' % f.name)
|
e.add(opts, '"%s": "choices" should be a sequence of two-item iterables (e.g. list of 2 item tuples).' % f.name)
|
||||||
if f.db_index not in (None, True, False):
|
if f.db_index not in (None, True, False):
|
||||||
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
|
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
|
||||||
|
|
||||||
|
|
|
@ -80,9 +80,10 @@ If a field has ``blank=False``, the field will be required.
|
||||||
|
|
||||||
.. attribute:: Field.choices
|
.. attribute:: Field.choices
|
||||||
|
|
||||||
An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this
|
An iterable (e.g., a list or tuple) consisting itself of iterables of exactly
|
||||||
field. If this is given, the default form widget will be a select box with
|
two items (e.g. ``[(A, B), (A, B) ...]``) to use as choices for this field. If
|
||||||
these choices instead of the standard text field.
|
this is given, the default form widget will be a select box with these choices
|
||||||
|
instead of the standard text field.
|
||||||
|
|
||||||
The first element in each tuple is the actual value to be stored, and the
|
The first element in each tuple is the actual value to be stored, and the
|
||||||
second element is the human-readable name. For example::
|
second element is the human-readable name. For example::
|
||||||
|
|
|
@ -238,6 +238,9 @@ Minor features
|
||||||
Meta option: ``localized_fields``. Fields included in this list will be localized
|
Meta option: ``localized_fields``. Fields included in this list will be localized
|
||||||
(by setting ``localize`` on the form field).
|
(by setting ``localize`` on the form field).
|
||||||
|
|
||||||
|
* The ``choices`` argument to model fields now accepts an iterable of iterables
|
||||||
|
instead of requiring an iterable of lists or tuples.
|
||||||
|
|
||||||
Backwards incompatible changes in 1.6
|
Backwards incompatible changes in 1.6
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
|
|
@ -375,8 +375,8 @@ invalid_models.fielderrors: "decimalfield3": DecimalFields require a "max_digits
|
||||||
invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than or equal to the value of the "decimal_places" attribute.
|
invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than or equal to the value of the "decimal_places" attribute.
|
||||||
invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
|
invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
|
||||||
invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
|
invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
|
||||||
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
|
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-item iterables (e.g. list of 2 item tuples).
|
||||||
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
|
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-item iterables (e.g. list of 2 item tuples).
|
||||||
invalid_models.fielderrors: "index": "db_index" should be either None, True or False.
|
invalid_models.fielderrors: "index": "db_index" should be either None, True or False.
|
||||||
invalid_models.fielderrors: "field_": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.
|
invalid_models.fielderrors: "field_": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.
|
||||||
invalid_models.fielderrors: "nullbool": BooleanFields do not accept null values. Use a NullBooleanField instead.
|
invalid_models.fielderrors: "nullbool": BooleanFields do not accept null values. Use a NullBooleanField instead.
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class ThingItem(object):
|
||||||
|
|
||||||
|
def __init__(self, value, display):
|
||||||
|
self.value = value
|
||||||
|
self.display = display
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (x for x in [self.value, self.display])
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
|
class Things(object):
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (x for x in [ThingItem(1, 2), ThingItem(3, 4)])
|
||||||
|
|
||||||
|
|
||||||
|
class ThingWithIterableChoices(models.Model):
|
||||||
|
|
||||||
|
# Testing choices= Iterable of Iterables
|
||||||
|
# See: https://code.djangoproject.com/ticket/20430
|
||||||
|
thing = models.CharField(max_length=100, blank=True, choices=Things())
|
|
@ -0,0 +1,14 @@
|
||||||
|
import io
|
||||||
|
|
||||||
|
from django.core import management
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class ModelValidationTest(TestCase):
|
||||||
|
|
||||||
|
def test_models_validate(self):
|
||||||
|
# All our models should validate properly
|
||||||
|
# Validation Tests:
|
||||||
|
# * choices= Iterable of Iterables
|
||||||
|
# See: https://code.djangoproject.com/ticket/20430
|
||||||
|
management.call_command("validate", stdout=io.BytesIO())
|
Loading…
Reference in New Issue