Skip to content

AttributeError Using .alias() On Polymorphic Querysets #658

@trumpet2012

Description

@trumpet2012

Using .alias() on a polymorphic queryset, causes an AttributeError to be thrown.

The workaround is to use annotate instead of alias.

Minimal reproduction using the example project from the repo:

from pexp.models import TestModelA, TestModelB
from django.db import models
from django.db.models import functions

TestModelB.objects.create(field1="field1", field2="field2")

# Evaluating this queryset throws the AttributeError
list(TestModelA.objects.alias(lower_field1=functions.Lower(models.F("field1"))))

The full traceback for the error:

AttributeError                            Traceback (most recent call last)
File ~/code/django-polymorphic/.venv/lib/python3.10/site-packages/IPython/core/formatters.py:770, in PlainTextFormatter.__call__(self, obj)
    763 stream = StringIO()
    764 printer = pretty.RepresentationPrinter(stream, self.verbose,
    765     self.max_width, self.newline,
    766     max_seq_length=self.max_seq_length,
    767     singleton_pprinters=self.singleton_printers,
    768     type_pprinters=self.type_printers,
    769     deferred_pprinters=self.deferred_printers)
--> 770 printer.pretty(obj)
    771 printer.flush()
    772 return stream.getvalue()

File ~/code/django-polymorphic/.venv/lib/python3.10/site-packages/IPython/lib/pretty.py:419, in RepresentationPrinter.pretty(self, obj)
    408                         return meth(obj, self, cycle)
    409                 if (
    410                     cls is not object
    411                     # check if cls defines __repr__
   (...)
    417                     and callable(_safe_getattr(cls, "__repr__", None))
    418                 ):
--> 419                     return _repr_pprint(obj, self, cycle)
    421     return _default_pprint(obj, self, cycle)
    422 finally:

File ~/code/django-polymorphic/.venv/lib/python3.10/site-packages/IPython/lib/pretty.py:794, in _repr_pprint(obj, p, cycle)
    792 """A pprint that just redirects to the normal repr function."""
    793 # Find newlines and replace them with p.break_()
--> 794 output = repr(obj)
    795 lines = output.splitlines()
    796 with p.group():

File ~/code/django-polymorphic/src/polymorphic/query.py:490, in PolymorphicQuerySet.__repr__(self, *args, **kwargs)
    488 def __repr__(self, *args, **kwargs):
    489     if self.model.polymorphic_query_multiline_output:
--> 490         result = ",\n  ".join(repr(o) for o in self.all())
    491         return f"[ {result} ]"
    492     else:

File ~/code/django-polymorphic/.venv/lib/python3.10/site-packages/django/db/models/query.py:384, in QuerySet.__iter__(self)
    369 def __iter__(self):
    370     """
    371     The queryset iterator protocol uses three nested iterators in the
    372     default case:
   (...)
    382            - Responsible for turning the rows into model objects.
    383     """
--> 384     self._fetch_all()
    385     return iter(self._result_cache)

File ~/code/django-polymorphic/.venv/lib/python3.10/site-packages/django/db/models/query.py:1949, in QuerySet._fetch_all(self)
   1947 def _fetch_all(self):
   1948     if self._result_cache is None:
-> 1949         self._result_cache = list(self._iterable_class(self))
   1950     if self._prefetch_related_lookups and not self._prefetch_done:
   1951         self._prefetch_related_objects()

File ~/code/django-polymorphic/src/polymorphic/query.py:63, in PolymorphicModelIterable._polymorphic_iterator(self, base_iter)
     60         reached_end = True
     61         break
---> 63 real_results = self.queryset._get_real_instances(base_result_objects)
     65 for o in real_results:
     66     yield o

File ~/code/django-polymorphic/src/polymorphic/query.py:460, in PolymorphicQuerySet._get_real_instances(self, base_result_objects)
    458 if self.query.annotations:
    459     for anno_field_name in self.query.annotations.keys():
--> 460         attr = getattr(base_object, anno_field_name)
    461         setattr(real_object, anno_field_name, attr)
    463 if self.query.extra_select:

AttributeError: 'TestModelA' object has no attribute 'lower_field1'

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions