#33596: Subsequent calls to prefetch_related_objects() don't work for model
instances that have changed.
-------------------------------------+-------------------------------------
     Reporter:  Dennis Kliban        |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  3.2
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Simon Charette):

 I wonder if this is actually a bug or we should ''wontfix'' this one.

 The definition of `is_fetched` for a prefetched relationship via `to_attr`
 is the presence of the attribute itself. The
 
[https://github.com/django/django/blob/1b695fbbc203c163bf7b8d78f6313a6c506fb938/django/db/models/fields/related_descriptors.py#L735
 many-to-many manager already takes care of clearing the prefetched objects
 that Django knows about when add is called] (`_prefetched_objects_cache`
 is under Django's control) but unless we introduce a way to do some
 bookeeping of the form `_prefetched_to_attrs: dict[prefetch_cache_name:
 str, to_attrs: list[str]]` when `to_attr` is used I don't see how we can
 fix this issue.

 Then comes the question of what to do if the property doesn't support
 `del` and documenting that this change now breaks patterns of the form

 {{{#!python
 bookings = Booking.objects.prefetch_related(
     'seats',
     Prefetch('seats', to_attr='existing_seats'),
 )
 sync_bookings(bookings)  # function that alters .seats one way or the
 other
 added_seats = []
 removed_seats = []
 for booking in bookings:
     added_seats.extend(set(booking.seats.all()) -
 set(booking.existing_seats))
     removed_seats.extend(set(booking.existing_seats) -
 set(booking.seats.all())
 }}}

 Since it's not obvious if `to_attr` should be cleared or not on a
 prefetched relationship change and we've defaulting to not doing so since
 the introduction of the feature I'd be inclined to ''wontfix'' this one
 and declare that it's the user responsibility to clear `to_attr` fetched
 relationships prior to attempting a second round of
 `prefetch_related_objects` and do the book keeping themselves:

 {{{#!diff
 diff --git a/tests/prefetch_related/test_prefetch_related_objects.py
 b/tests/prefetch_related/test_prefetch_related_objects.py
 index 8be643e6dc..edd0bffe2f 100644
 --- a/tests/prefetch_related/test_prefetch_related_objects.py
 +++ b/tests/prefetch_related/test_prefetch_related_objects.py
 @@ -151,6 +151,7 @@ def
 test_prefetch_object_to_attr_twice_with_change(self):
              )
              self.assertCountEqual(book.the_authors, [])
          book.authors.add(author)
 +        del book.the_authors
          with self.assertNumQueries(1):
              prefetch_related_objects(
                  [book],
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33596#comment:2>
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 view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107017fbc5a248d-7370e447-7af0-4cc3-ae56-b0c806f4817b-000000%40eu-central-1.amazonses.com.

Reply via email to