Opened 8 months ago

Closed 8 months ago

#35257 closed Bug (fixed)

db.models.expressions _connector_combinations for Numeric with NULL returns only FloatField instead of (IntegerField, DecimalField, FloatField)

Reported by: Sharon Woo Owned by: Sharon Woo
Component: Database layer (models, ORM) Version: 5.0
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Discovered via writing tests for this related ticket with a LOT of help from David Sanders -- https://code.djangoproject.com/ticket/35235.

In https://github.com/django/django/blob/ef2434f8508551fee183079ab471b1dc325c7acb/django/db/models/expressions.py#L599-L613 via https://github.com/django/django/pull/15271,

the dictionary comprehension below

 {
        connector: [
            (field_type, NoneType, field_type),
            (NoneType, field_type, field_type),
        ]
        for connector in (
            Combinable.ADD,
            Combinable.SUB,
            Combinable.MUL,
            Combinable.DIV,
            Combinable.MOD,
            Combinable.POW,
        )
        for field_type in (fields.IntegerField, fields.DecimalField, fields.FloatField)
    },

returns

Combinable.ADD: [(fields.FloatField, NoneType, fields.FloatField),
                     (NoneType, fields.FloatField, fields.FloatField),],
Combinable.SUB: [(fields.FloatField, NoneType, fields.FloatField),
                     (NoneType, fields.FloatField, fields.FloatField),],
...

instead of the expected

Combinable.ADD: [(fields.IntegerField, NoneType, fields.IntegerField),
                     (NoneType, fields.IntegerField, fields.IntegerField),
                     (fields.DecimalField, NoneType, fields.DecimalField),
                     (NoneType, fields.DecimalField, fields.DecimalField),
                     (fields.FloatField, NoneType, fields.FloatField),
                     (NoneType, fields.FloatField, fields.FloatField),
                     ],
...

This leads to only FloatField throwing FieldError with _output_field_or_none when fields are combined with NULL.

Examples you can run right now:

original_dict_comp = {
        connector: (
            (field_type, None, field_type),
            (None, field_type, field_type),
        )
        for connector in (
        'ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW',
        )
        for field_type in ('IntegerField', 'DecimalField', 'FloatField')
    }

# there are a few ways to write this one
fixed_dict_comp = {
    key: [
        (field_type, None, field_type)
        for field_type in ['IntegerField', 'DecimalField', 'FloatField']
    ] + [
        (None, field_type, field_type)
        for field_type in ['IntegerField', 'DecimalField', 'FloatField']
    ]
    for key in ['ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW']
}

Change History (6)

comment:1 by David Sanders, 8 months ago

Triage Stage: UnreviewedAccepted

comment:2 by Sharon Woo, 8 months ago

Owner: changed from nobody to Sharon Woo

comment:3 by Sharon Woo, 8 months ago

Has patch: set

PR in progress, comments very welcome.

comment:4 by Mariusz Felisiak, 8 months ago

Patch needs improvement: set

comment:5 by Mariusz Felisiak, 8 months ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:6 by Mariusz Felisiak <felisiak.mariusz@…>, 8 months ago

Resolution: fixed
Status: assignedclosed

In 6a37e9b:

Fixed #35257 -- Corrected resolving output_field for IntegerField/DecimalField with NULL.

Note: See TracTickets for help on using tickets.
Back to Top