#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 [email protected].
To post to this group, send email to [email protected].
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.