#30493: GenericRelation and prefetch_related: wrong caching with cyclic 
prefetching
-------------------------------------+-------------------------------------
               Reporter:  Finn       |          Owner:  nobody
  Stutzenstein                       |
                   Type:  Bug        |         Status:  new
              Component:             |        Version:  2.2
  contrib.contenttypes               |       Keywords:  GenericRelation
               Severity:  Normal     |  prefetch_related
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Hello @all!

 I encountered an issue with GenericRelations. Here is an example to
 reproduce this issue:
 https://github.com/FinnStutzenstein/GenericRelatedPrefetch
 Just do a migrate and runserver. The code showing the error is started
 automatically in main/apps.py. Please start with --noreload not to have
 the output twice.

 Whats the problem?
 I have a generic model (Tag) that have a {{{content_object}}}. Then there
 are multiple (in the example 2) models, Book and CD, that have exactly one
 tag assigned. In the real application (OpenSlides) this invariant is
 ensured in other places; in the example the objects are created in a way,
 that this invariant holds.

 All these content objects have a property {{{tag}}}, that should return
 the one assigned tag. This is done by adding a helper field
 {{{tags=GenericRelation(Tag)}}} and the property accesses
 {{{self.tags.all()[0]}}}. The {{{.all()[0]}}} instead of a simple
 {{{.get()}}} is required for the prefetching to work. See main/models.py
 in the example.

 Now all tags should be loaded because in OpenSlides they would be
 serialized. For each tag the {{{content_object}}} is accessed as well as
 {{{content_object.tag}}}. Because this would result in many DB queries (in
 the real application about 10000 Tags, and in sum 10000 content objects)
 the models are prefetched with:
 {{{Tag.objects.prefetch_related("content_object",
 "content_object__tag")}}} (Note: The executed code is in main/apps.py).
 This results in a constant amount of queries (4 in this case) instead of
 something proportional to the amount of objects. In the example you can
 set {{{N}}}, the amount of objects created, to a higher amount to verify,
 that the amount of queries stays constant.

 What is expected: If I have a tag {{{tag}}}, {{{tag.content_object.tag}}}
 should be equal to {{{tag}}}.
 Output from the example (with N=1):

 {{{
 Got 'Tag to book0':
     -the content object: Book0
     -the content objects tag (should be the same as 'Tag to book0'!):Tag
 to book0
 Got 'Tag to cd0':
     -the content object: CD0
     -the content objects tag (should be the same as 'Tag to cd0'!):Tag to
 book0
 }}}

 This is not the case: 'Tag to cd1' -> 'cd1' -> 'Tag to book1'.

 I tracked this a bit showing, that {{{_prefetched_objects_cache}}} holds
 the wrong value, which is accessed through {{{.all()}}} ->
 {{{.get_queryset()}}} where the cached/prefetched result is taken.

 Thanks!

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

Reply via email to