Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#31773 closed Bug (fixed)

ExpressionWrapper loses output_field for combined expression without an output_field.

Reported by: Thodoris Sotiropoulos Owned by: Mariusz Felisiak
Component: Database layer (models, ORM) Version: 3.1
Severity: Release blocker 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

I have the following model.

class Mallets(models.Model):
    id = models.AutoField(primary_key=True,blank=True, null=True)
    hindsight = models.ForeignKey(Hindsight, models.DO_NOTHING, blank=True, null=True)
    believer = models.IntegerField(blank=True, null=True)
    damnably = models.IntegerField(blank=True, null=True)
    issue = models.IntegerField(blank=True, null=True)
    glover = models.TextField(blank=True, null=True)  # This field type is a guess.

    class Meta:
        db_table = 'mallets'

and I perform the following query on Django 3.2

sheer = ExpressionWrapper((F('issue') / F('id')), output_field=FloatField())
lacquer = ExpressionWrapper(Avg(F('sheer'), output_field=FloatField()), output_field=TextField())
q = Mallets.objects.using('default')
ret = q.annotate(sheer=sheer).values('sheer').annotate(lacquer=Sum(F('believer'))).order_by('sheer').first()

Django however throws the following exception

Traceback (most recent call last):
  File "driver_sqlite.py", line 25, in <module>
    ret2 = ret1.annotate(sheer=sheer).values('sheer').annotate(lacquer=Sum('believer')).order_by('sheer').first()
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/query.py", line 678, in first
    for obj in (self if self.ordered else self.order_by('pk'))[:1]:
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/query.py", line 287, in __iter__
    self._fetch_all()
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/query.py", line 1305, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/query.py", line 111, in __iter__
    for row in compiler.results_iter(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size):
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/sql/compiler.py", line 1113, in results_iter
    results = self.execute_sql(MULTI, chunked_fetch=chunked_fetch, chunk_size=chunk_size)
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/sql/compiler.py", line 1148, in execute_sql
    sql, params = self.as_sql()
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/sql/compiler.py", line 498, in as_sql
    extra_select, order_by, group_by = self.pre_sql_setup()
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/sql/compiler.py", line 60, in pre_sql_setup
    group_by = self.get_group_by(self.select + extra_select, order_by)
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/sql/compiler.py", line 142, in get_group_by
    sql, params = expr.select_format(self, sql, params)
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/expressions.py", line 388, in select_format
    if hasattr(self.output_field, 'select_format'):
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/expressions.py", line 269, in output_field
    output_field = self._resolve_output_field()
  File "/home/.env/lib/python3.6/site-packages/Django-3.2-py3.6.egg/django/db/models/expressions.py", line 309, in _resolve_output_field
    source.__class__.__name__,
django.core.exceptions.FieldError: Expression contains mixed types: IntegerField, AutoField. You must set output_field.

Note that when I run the query above on Django 3.0.8, this query runs as expected. So is this a regression in Django 3.2?

Change History (5)

comment:1 by Mariusz Felisiak, 4 years ago

Owner: changed from nobody to Mariusz Felisiak
Severity: NormalRelease blocker
Status: newassigned
Summary: Django throws django.core.exceptions.FieldError: Expression contains mixed types: IntegerField, AutoField.ExpressionWrapper loses output_field for combined expression without an output_field.
Triage Stage: UnreviewedAccepted
Type: UncategorizedBug
Version: master3.1

comment:2 by Mariusz Felisiak, 4 years ago

Has patch: set

comment:3 by Carlton Gibson, 4 years ago

Triage Stage: AcceptedReady for checkin

comment:4 by GitHub <noreply@…>, 4 years ago

Resolution: fixed
Status: assignedclosed

In 8a6df55f:

Fixed #31773 -- Fixed preserving output_field in ExpressionWrapper for combined expressions.

Thanks Thodoris Sotiropoulos for the report and Simon Charette for the
implementation idea.

Regression in df32fd42b84cc6dbba173201f244491b0d154a63.

comment:5 by Mariusz Felisiak <felisiak.mariusz@…>, 4 years ago

In e6285cac:

[3.1.x] Fixed #31773 -- Fixed preserving output_field in ExpressionWrapper for combined expressions.

Thanks Thodoris Sotiropoulos for the report and Simon Charette for the
implementation idea.

Regression in df32fd42b84cc6dbba173201f244491b0d154a63.
Backport of 8a6df55f2dd5131282084a4edfd48f63fbf8c69a from master

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