#33835: Select_related().only() in the Prefetch class increases the number of
queries for the InverseManyToOne relation.
-------------------------------------+-------------------------------------
               Reporter:  Ipakeev    |          Owner:  nobody
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  dev
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 I'm trying to optimize graphQL queries. When I use Prefetch with
 **select_related** and **only** optimizations, I encounter an increase in
 database queries. This is because I'm prefetching Book via
 InverseManyToOne relation and It needs a **publisher_id** in the **only**
 method.
 {{{
 class Author(models.Model):
     name = models.CharField(max_length=32)


 class Book(models.Model):
     title = models.CharField(max_length=32)
     author = models.ForeignKey("Author", on_delete=models.CASCADE)
     publisher = models.ForeignKey(
         "Publisher",
         on_delete=models.CASCADE,
         related_name="books",
     )


 class Publisher(models.Model):
     address = models.CharField(max_length=32)


 class AuthorType(DjangoObjectType):
     class Meta:
         model = Author


 class BookType(DjangoObjectType):
     class Meta:
         model = Book


 class PublisherType(DjangoObjectType):
     class Meta:
         model = Publisher
 }}}


 Fill in the database:
 {{{
         with transaction.atomic():
             authors = Author.objects.bulk_create([
                 Author(name=f"Name{i}") for i in range(10)
             ])
             publishers = Publisher.objects.bulk_create([
                 Publisher(address=f"Address{i}") for i in range(10)
             ])
             Book.objects.bulk_create([
                 Book(
                     title=f"Title{i}",
                     author=random.choice(authors),
                     publisher=random.choice(publishers),
                 ) for i in range(20)
             ])
 }}}


 GraphQL query:
 {{{
 {
   publishers {
     address
     books {
       title
       author {
         name
       }
     }
   }
 }
 }}}


 22 db queries:
 {{{
 class Query(graphene.ObjectType):
     publishers = graphene.List(PublisherType)

     def resolve_publishers(self, info):
         queryset = Book.objects.select_related("author").only("title",
 "author__name")
         return Publisher.objects.prefetch_related(Prefetch("books",
 queryset)).only("address")
 }}}

 2 db queries:
 {{{
 class Query(graphene.ObjectType):
     publishers = graphene.List(PublisherType)

     def resolve_publishers(self, info):
         queryset = Book.objects.select_related("author").only("title",
 "author__name", "publisher_id")
         return Publisher.objects.prefetch_related(Prefetch("books",
 queryset)).only("address")
 }}}

 I fixed function **prefetch_related_objects** at django/db/models/query.py
 and now I don't need **publisher_id** in **only** method:
 {{{
 ...
 prefetcher, descriptor, attr_found, is_fetched = get_prefetcher(
     first_obj, through_attr, to_attr
 )

 from django.db.models.fields.related_descriptors import
 ReverseManyToOneDescriptor
 if type(descriptor) is ReverseManyToOneDescriptor:
 lookup.queryset.query.deferred_loading[0].add(descriptor.field.attname)

 if not attr_found:
     raise AttributeError(
 ...
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33835>
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/01070181df4ec14c-0553a6c8-b9aa-44f4-b755-ba62040b91c9-000000%40eu-central-1.amazonses.com.

Reply via email to