Opened 3 months ago

Last modified 8 days ago

#28748 assigned Bug

Named groups in choices are not properly validated

Reported by: Scott Stevens Owned by: François Freitag
Component: Database layer (models, ORM) Version: 2.0
Severity: Normal Keywords: choices
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no


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 ./ makemigrations to run successfully (the check is not performed when launching ./ 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\", line 1144, in full_clean
  File ...\django\db\models\", line 1186, in clean_fields
    setattr(self, f.attname, f.clean(raw_value, self))
  File "...\django\db\models\fields\", line 607, in clean
    self.validate(value, model_instance)
  File "...\django\db\models\fields\", 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 [
      "'choices' must be an iterable containing "
      "(actual value, human readable name) tuples.",

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.

Change History (5)

comment:1 Changed 3 months ago by Tim Graham

Triage Stage: UnreviewedAccepted

comment:2 Changed 3 months ago by Aaron Kirkbride

Owner: changed from nobody to Aaron Kirkbride
Status: newassigned

comment:3 Changed 2 months ago by Aaron Kirkbride

Owner: Aaron Kirkbride deleted
Status: assignednew

comment:4 Changed 6 weeks ago by François Freitag

Has patch: set
Owner: set to François Freitag
Status: newassigned

comment:5 Changed 8 days ago by Tim Graham

Patch needs improvement: set
Note: See TracTickets for help on using tickets.
Back to Top