#35677: Unexpected behaviour of Prefetch with queryset filtering on a through 
model
-------------------------------------+-------------------------------------
     Reporter:  David Glenck         |                    Owner:  (none)
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  5.1
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:  Prefetch,            |             Triage Stage:  Accepted
  prefetch_related, many-to-many     |
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

 * resolution:  needsinfo =>
 * stage:  Unreviewed => Accepted
 * status:  closed => new

Comment:

 I think the following is what you are requesting. I'm re-opening Natalia
 as I believe this is a legitimate bug.

 {{{#!diff
 diff --git a/django/db/models/fields/related_descriptors.py
 b/django/db/models/fields/related_descriptors.py
 index bc288c47ec..5356e28d22 100644
 --- a/django/db/models/fields/related_descriptors.py
 +++ b/django/db/models/fields/related_descriptors.py
 @@ -94,9 +94,9 @@ def __set__(self, instance, value):
          instance.__dict__[self.field.attname] = value


 -def _filter_prefetch_queryset(queryset, field_name, instances):
 +def _filter_prefetch_queryset(queryset, field_name, instances, db):
      predicate = Q(**{f"{field_name}__in": instances})
 -    db = queryset._db or DEFAULT_DB_ALIAS
 +    db = db or DEFAULT_DB_ALIAS
      if queryset.query.is_sliced:
          if not connections[db].features.supports_over_clause:
              raise NotSupportedError(
 @@ -785,12 +785,15 @@ def get_prefetch_querysets(self, instances,
 querysets=None):
                  )
              queryset = querysets[0] if querysets else
 super().get_queryset()
              queryset._add_hints(instance=instances[0])
 -            queryset = queryset.using(queryset._db or self._db)
 +            db = queryset._db or self._db
 +            queryset = queryset.using(db)

              rel_obj_attr = self.field.get_local_related_value
              instance_attr = self.field.get_foreign_related_value
              instances_dict = {instance_attr(inst): inst for inst in
 instances}
 -            queryset = _filter_prefetch_queryset(queryset,
 self.field.name, instances)
 +            queryset = _filter_prefetch_queryset(
 +                queryset, self.field.name, instances, db
 +            )

              # Since we just bypassed this class' get_queryset(), we must
 manage
              # the reverse relation manually.
 @@ -1165,10 +1168,15 @@ def get_prefetch_querysets(self, instances,
 querysets=None):
                  )
              queryset = querysets[0] if querysets else
 super().get_queryset()
              queryset._add_hints(instance=instances[0])
 -            queryset = queryset.using(queryset._db or self._db)
 +            db = queryset._db or self._db
 +            # Make sure filters are applied in a "sticky" fashion to
 reuse
 +            # multi-valued relationships like direct filter() calls
 against
 +            # many-to-many managers do.
 +            queryset.query.filter_is_sticky = True
              queryset = _filter_prefetch_queryset(
 -                queryset._next_is_sticky(), self.query_field_name,
 instances
 +                queryset, self.query_field_name, instances, db
              )
 +            queryset = queryset.using(db)

              # M2M: need to annotate the query in order to get the primary
 model
              # that the secondary model was actually related to. We know
 that
 }}}

 David, if you'd up to it it seems that all this bugfix is missing are
 tests that can be added to the `prefetch_related` test app if you're
 interested in submitting a PR once Github is back online.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/35677#comment:5>
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/01070191536e2e10-fd6b182e-ec2f-4609-a595-498e4ee19bda-000000%40eu-central-1.amazonses.com.

Reply via email to