﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
26916	Prefetch's to_attr does not write into cached_properties in 1.10	karyon	Simon Charette	"consider code like this


{{{
Model A:
    some_attribute = models.ManyToManyField(B, ...)

    @cached_property
    def filtered_attribute(self):
        return self.some_attribute.filter(...)

# this manually fills some_attribute for all objects with a single additional query.
all_of_a = A.objects.prefetch_related(Prefetch(""some_attribute"", queryset=B.objects.filter(...), to_attr=""filtered_attribute""))

for a in all_of_a:
    # since we have cached some_attribute, no additional db hits here.
    do_stuff_with(a.some_attribute)
}}}

untested code, i hope the intent is clear. actual code: [https://github.com/fsr-itse/EvaP/blob/b6222413f15fc7256622a31f7045046f7be1e466/evap/staff/views.py#L58 prefetch] and the [https://github.com/fsr-itse/EvaP/blob/b6222413f15fc7256622a31f7045046f7be1e466/evap/evaluation/models.py#L387 property]

i thought this ""hack"" made sense since you can assign cached properties with the = operator just fine, so why not let prefetch_related do exactly that?

this used to work with django 1.9, whereas in django 1.10, the cached property does not seem to be written to.

this first regressed in bdbe50a491ca41e7d4ebace47bfe8abe50a58211, example stacktrace (code is in the ""prefetch"" link above):
{{{
...
File ""/vagrant/evap/staff/views.py"", line 80, in semester_view
  courses = get_courses_with_prefetched_data(semester)
File ""/vagrant/evap/staff/views.py"", line 65, in get_courses_with_prefetched_data
  course.general_contribution = course.general_contribution[0]
File ""/vagrant/src/django/django/utils/functional.py"", line 35, in __get__
  res = instance.__dict__[self.name] = self.func(instance)
File ""/vagrant/evap/evaluation/models.py"", line 390, in general_contribution
  return self.contributions.get(contributor=None)
File ""/vagrant/src/django/django/db/models/manager.py"", line 85, in manager_method
  return getattr(self.get_queryset(), name)(*args, **kwargs)
AttributeError: 'list' object has no attribute 'get'
}}}
it actually executes the cached_property although i expected it to return the cached value. what the actual problem is i don't know.

error message changed in 53a5fb3cc0137bebeebc0d4d321dbfe20397b065, stack trace:
{{{
...
File ""/vagrant/evap/staff/views.py"", line 80, in semester_view
  courses = get_courses_with_prefetched_data(semester)
File ""/vagrant/evap/staff/views.py"", line 65, in get_courses_with_prefetched_data
  course.general_contribution = course.general_contribution[0]
TypeError: 'Contribution' object does not support indexing
}}}
here it seems to execute the cached_property successfully, returning a single element, and then failing at the [0]. again i expected it to return the cached value, which would be a list or queryset."	Bug	closed	Database layer (models, ORM)	1.10	Release blocker	fixed		karyon Simon Charette	Ready for checkin	1	0	0	0	0	0
