#26916: Prefetch's to_attr does not write into cached_properties in 1.10
-------------------------------+--------------------
     Reporter:  karyon         |      Owner:  nobody
         Type:  Bug            |     Status:  new
    Component:  Uncategorized  |    Version:  1.10
     Severity:  Normal         |   Keywords:
 Triage Stage:  Unreviewed     |  Has patch:  0
Easy pickings:  0              |      UI/UX:  0
-------------------------------+--------------------
 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.

--
Ticket URL: <https://code.djangoproject.com/ticket/26916>
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/049.042562b6585c8adcafafb94919574aff%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to