﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
28748	Named groups in choices are not properly validated	Scott Stevens	François Freitag	"When using named groups for the `choices` attribute, I accidentally created them incorrectly, like so:

{{{
tournament = models.PositiveSmallIntegerField(db_index=True, choices=(
    (4, 'g'),
    ('NamedTuple', (5, 'h'), ),
))
}}}

Given that specifying `choices` as `(4, 'g'), ('NamedTuple', (5, 'h'), (6, 'i'), ),` raises `E.005` (as does `1, 2, 3,`), I would expect the same result for these malformed named groups.

Instead, it allows `./manage.py makemigrations` to run successfully (the check is not performed when launching `./manage.py shell`, which might be its own issue). However, it raises this exception when performing a `full_clean()` on a model and thus validating the field in question (assuming the field has been set):

{{{
  File ""...\django\db\models\base.py"", line 1144, in full_clean
    self.clean_fields(exclude=exclude)
  File ...\django\db\models\base.py"", line 1186, in clean_fields
    setattr(self, f.attname, f.clean(raw_value, self))
  File ""...\django\db\models\fields\__init__.py"", line 607, in clean
    self.validate(value, model_instance)
  File ""...\django\db\models\fields\__init__.py"", line 583, in validate
    for optgroup_key, optgroup_value in option_value:
TypeError: 'int' object is not iterable
}}}

The `flatchoices` attribute ends up as `[5, 'h', (4, 'g')]`.

It is my understanding that this behaviour is unintended, as the `_check_choices()` method performs validation on the `choices` attribute.

Specifically, this clause

{{{
elif any(isinstance(choice, str) or
    not is_iterable(choice) or len(choice) != 2
    for choice in self.choices):
  return [
    checks.Error(
      ""'choices' must be an iterable containing ""
      ""(actual value, human readable name) tuples."",
      obj=self,
      id='fields.E005',
    )
  ]
}}}


Does not check beyond the length of each choice, even if that ""choice"" is a named group.

This can be further seen with this set of choices:

{{{
tournament = models.PositiveSmallIntegerField(db_index=True, choices=(
  (4, 'g'),
  ('NamedTuple', (
    (5, 'h'),
    (2, 3, 4, ),
  )),
))
}}}

Migrations are again created successfully, but when validating the field, it raises
{{{ ValueError: too many values to unpack (expected 2) }}}
on the same line as before."	Bug	closed	Database layer (models, ORM)	dev	Normal	fixed	choices		Accepted	1	0	0	0	0	0
