#26565: Allow Prefetch query to returns aggregations ----------------------------------------------+---------------------------- Reporter: mlorant | Owner: nobody Type: Bug | Status: new Component: Database layer (models, ORM) | Version: 1.9 Severity: Normal | Keywords: prefetch, | values Triage Stage: Unreviewed | Has patch: 0 Easy pickings: 0 | UI/UX: 0 ----------------------------------------------+---------------------------- I came across a use case that does not seems to be possible using the Django ORM on Django 1.9.
Let's says I want to get all objects from a `Order` model and prefetch for each order all pay lines, grouped per code, to get a list similar to: `[{'code': 'A', 'number': 3, 'amount': 1000}, {'code': 'B', 'number': 1, 'amount': 5000}]` if the order has four PayRollLine associated, with 3 where code=A and 1 where code=B. {{{ # Query that will be used inside the `Prefetch` object later # Let's assume quantity and unit_amount can't be null in the query # to avoid extra Coalesce... prefetch_qs = ( PayrollLine.objects.values('code').annotate( number=ExpressionWrapper( Sum(F('quantity')), output_field=DecimalField() ), amount=ExpressionWrapper( Sum(F('unit_amount') * F('quantity')), output_field=DecimalField() ), ) ) print( Order.objects.all() .prefetch_related( Prefetch('pay_lines', queryset=prefetch_qs, to_attr='pay_lines_grouped') ) ) }}} The first query works fine alone, outside the prefetch object. But, when executing the second query, Django raises an exception: {{{ Traceback (most recent call last): [...] File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/query.py", line 234, in __repr__ data = list(self[:REPR_OUTPUT_SIZE + 1]) File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/query.py", line 258, in __iter__ self._fetch_all() File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/query.py", line 1076, in _fetch_all self._prefetch_related_objects() File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/query.py", line 656, in _prefetch_related_objects prefetch_related_objects(self._result_cache, self._prefetch_related_lookups) File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/query.py", line 1457, in prefetch_related_objects obj_list, additional_lookups = prefetch_one_level(obj_list, prefetcher, lookup, level) File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/query.py", line 1556, in prefetch_one_level prefetcher.get_prefetch_queryset(instances, lookup.get_current_queryset(level))) File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/fields/related_descriptors.py", line 544, in get_prefetch_queryset instance = instances_dict[rel_obj_attr(rel_obj)] File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/fields/related.py", line 597, in get_local_related_value return self.get_instance_value_for_fields(instance, self.local_related_fields) File "/data/.virtualenvs/ORFEO/local/lib/python2.7/site- packages/django/db/models/fields/related.py", line 605, in get_instance_value_for_fields opts = instance._meta AttributeError: 'dict' object has no attribute '_meta' }}} Looks like Django can't work with dict in prefetch_related... On IRC, someone point me to [this PR](https://github.com/django/django/pull/6478) that could resolve my problem but I think it should be verified with unit tests. -- Ticket URL: <https://code.djangoproject.com/ticket/26565> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/050.275dd503dcd42166eb62ebea25af54a9%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.